Coverage for larch/plot/plotly_xafsplots.py: 0%

611 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-10-16 21:04 +0000

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 

26 

27from larch import Group 

28from larch.math import index_of 

29from larch.xafs import cauchy_wavelet, etok 

30 

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

32 pass 

33 

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

35 

36HAS_PLOTLY = True 

37try: 

38 import plotly 

39except ImportError: 

40 HAS_PLOTLY = False 

41 

42if HAS_PLOTLY: 

43 import plotly.graph_objs as pgo 

44 from plotly.subplots import make_subplots 

45 

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

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

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

49NCOLORS = len(LineColors) 

50NSTYLES = len(LineStyles) 

51 

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

53 showlegend=True, hovermode='closest', 

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

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

56 plot_bgcolor='#FDFDFF', 

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

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

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

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

61 ) 

62 

63def set_label_weight(label, w): 

64 return label.replace('_w_', '{0:g}'.format(w)) 

65 

66# common XAFS plot labels 

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

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

69 

70 Arguments 

71 ---------- 

72 kweight k-weight to use (required) 

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

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

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

76 """ 

77 ylab = [] 

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

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

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

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

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

83#enddef 

84 

85# note: 

86# to make life easier for MathJax/Plotly/IPython 

87# we have just replaced "\AA" with "\unicode{x212B}" 

88plotlabels = Group(k = r'$k \rm\,(\unicode{x212B}^{-1})$', 

89 r = r'$R \rm\,(\unicode{x212B})$', 

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

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

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

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

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

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

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

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

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

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

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

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

102 chikw = r'$k^{{_w_}}\chi(k) \rm\,(\unicode{x212B}^{{-_w_}})$', 

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

104 chi1 = r'$k\chi(k) \rm\,(\unicode{x212B}^{-1})$', 

105 chi2 = r'$k^2\chi(k) \rm\,(\unicode{x212B}^{-2})$', 

106 chi3 = r'$k^3\chi(k) \rm\,(\unicode{x212B}^{-3})$', 

107 chir = r'$\chi(R) \rm\,(\unicode{x212B}^{{-_w_}})$', 

108 chirmag = r'$|\chi(R)| \rm\,(\unicode{x212B}^{{-_w_}})$', 

109 chirre = r'${{\rm Re}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$', 

110 chirim = r'${{\rm Im}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$', 

111 chirpha = r'${{\rm Phase}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$', 

112 e0color = '#B2B282', 

113 chirlab = chirlab) 

114 

115 

116def safetitle(t): 

117 if "'" in t: 

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

119 return t 

120 

121def _get_title(dgroup, title=None): 

122 """get best title for group""" 

123 if title is not None: 

124 return safetitle(title) 

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

126 

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

128 t = getattr(dgroup, attr, None) 

129 if t is not None: 

130 if attr == 'filename': 

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

132 if folder == '': 

133 t = file 

134 else: 

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

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

137 return safetitle(t) 

138 if data_group is not None: 

139 t = getattr(data_group, attr, None) 

140 if t is not None: 

141 return t 

142 return safetitle(repr(dgroup)) 

143 

144 

145def _get_kweight(dgroup, kweight=None): 

146 if kweight is not None: 

147 return kweight 

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

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

150 return ftargs['kweight'] 

151 

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

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

154 values relative to e0. 

155 """ 

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

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

158 if emin is not None: 

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

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

161 emin += e0 

162 else: 

163 emin = dat_emin 

164 if emax is not None: 

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

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

167 emax += e0 

168 else: 

169 emax = dat_emax 

170 return emin, emax 

171 

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

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

174 xeps = min(np.diff(x)) / 5. 

175 if xmin is None: 

176 xmin = min(x) 

177 if xmax is None: 

178 xmax = max(x) 

179 

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

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

182 

183 i0 = index_of(x, xmin + xeps) 

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

185 

186 xspan = x[i0:i1] 

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

188 yspan = y[i0:i1] 

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

190 

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

192 max(xspan) + extend * xrange, 

193 min(yspan) - extend * yrange, 

194 max(yspan) + extend * yrange) 

195 

196 

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

198 dymin=None, dymax=None, 

199 show_legend=True, stacked=False): 

200 pass 

201 

202 

203class PlotlyFigure: 

204 """wrapping of Plotly Figure 

205 """ 

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

207 self.two_yaxis = two_yaxis 

208 self.style = deepcopy(FIGSTYLE) 

209 if style is not None: 

210 self.style.update(style) 

211 if self.two_yaxis: 

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

213 else: 

214 self.fig = pgo.FigureWidget() 

215 

216 self.traces = [] 

217 

218 def clear(self): 

219 self.traces = [] 

220 

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

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

223 itrace = len(self.traces) 

224 

225 if label is None: 

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

227 if color is None: 

228 color = LineColors[itrace % NCOLORS] 

229 if style is None: 

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

231 

232 trace_opts = {} 

233 if self.two_yaxis: 

234 trace_opts['secondary_y'] = (side.lower().startswith('r')) 

235 

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

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

238 

239 self.traces.append(trace) 

240 

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

242 

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

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

245 

246 def set_xrange(self, xmin, xmax): 

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

248 

249 def set_yrange(self, ymin, ymax): 

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

251 

252 def set_ylog(self, ylog=True): 

253 ytype = 'log' if ylog else 'linear' 

254 self.fig.update_yaxes(type=ytype) 

255 

256 def set_style(self, **kws): 

257 self.style.update(**kws) 

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

259 

260 def show(self, title=None, xlabel=None, ylabel=None, 

261 xmin=None, xmax=None, ymin=None, ymax=None, show=True): 

262 self.set_style(title=title, xaxis_title=xlabel, yaxis_title=ylabel) 

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

264 self.set_xrange(xmin, xmax) 

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

266 self.set_yrange(ymin, ymax) 

267 if show: 

268 self.fig.show() 

269 return self 

270 

271def plot(xdata, ydata, dy=None, fig=None, label=None, xlabel=None, 

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

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

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

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

276 show_legend=None, bgcolor=None, framecolor=None, gridcolor=None, 

277 textcolor=None, labelfontsize=None, titlefontsize=None, 

278 legendfontsize=None, fullbox=None, axes_style=None, zorder=None, show=True): 

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

280 

281 if fig is None: 

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

283 

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

285 style=style, marker=marker, side=side) 

286 

287 return fig.show(title=title, xlabel=xlabel, ylabel=ylabel, 

288 xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, show=show) 

289 

290 

291def multi_plot(plotsets): 

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

293 multiplot calls to plot: 

294 

295 instead of 

296 

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

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

299 

300 you can do 

301 

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

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

304 

305 """ 

306 two_axis = False 

307 for pset in plotsets[:]: 

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

309 if side == 'right': 

310 two_axis = True 

311 

312 

313 fig = PlotlyFigure(two_yaxis=two_axis) 

314 fig.clear() 

315 

316 sopts = dict(title=None, xlabel=None, ylabel=None) 

317 ropts = dict(xmin=None, xmax=None, ymin=None, ymax=None) 

318 

319 for pset in plotsets[:]: 

320 xdata = pset['xdata'] 

321 ydata = pset['ydata'] 

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

323 linewidth=3, marker=None) 

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

325 if w in pset: 

326 popts[w] = pset[w] 

327 for w in ('title', 'xlabel', 'ylabel'): 

328 if w in pset: 

329 sopts[w] = pset[w] 

330 

331 for w in ('xmin', 'xmax', 'ymin', 'ymax'): 

332 if w in pset: 

333 ropts[w] = pset[w] 

334 

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

336 

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

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

339 fig.style.update(sopts) 

340 return fig.show(**ropts) 

341 

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

343 show_pre=False, show_post=False, show_e0=False, with_deriv=False, 

344 emin=None, emax=None, label='mu', offset=0, title=None, fig=None, show=True): 

345 """ 

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

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

348 show=True, fig=None) 

349 

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

351 

352 Arplguments 

353 ---------- 

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

355 show_norm bool whether to show normalized data [False] 

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

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

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

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

360 show_e0 bool whether to show E0 [False] 

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

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

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

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

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

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

367 show display the PlotlyFig now [True] 

368 fig PlotlyFig to reuse [None] 

369 

370 Notes 

371 ----- 

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

373 energy, mu, norm, e0, pre_edge, edge_step 

374 """ 

375 if not HAS_PLOTLY: 

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

377 return 

378 

379 if hasattr(dgroup, 'mu'): 

380 mu = dgroup.mu 

381 elif hasattr(dgroup, 'mutrans'): 

382 mu = dgroup.mutrans 

383 elif hasattr(dgroup, 'mufluor'): 

384 mu = dgroup.mufluor 

385 else: 

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

387 #endif 

388 ylabel = plotlabels.mu 

389 if label is None: 

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

391 #endif 

392 if show_deriv: 

393 mu = dgroup.dmude 

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

395 dlabel = plotlabels.dmude 

396 elif show_norm: 

397 mu = dgroup.norm 

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

399 dlabel = plotlabels.norm 

400 #endif 

401 elif show_flat: 

402 mu = dgroup.flat 

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

404 dlabel = plotlabels.flat 

405 #endif 

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

407 title = _get_title(dgroup, title=title) 

408 

409 if fig is None: 

410 fig = PlotlyFigure(two_yaxis=with_deriv) 

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

412 

413 if with_deriv: 

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

415 fig.fig.update_yaxis(title_text=plotlabels.dmude, secondary_y=True) 

416 else: 

417 if not show_norm and show_pre: 

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

419 if not show_norm and show_post: 

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

421 

422 if show_e0: 

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

424 

425 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=ylabel, 

426 xmin=emin, xmax=emax, show=show) 

427 

428 

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

430 label=None, title=None, offset=0): 

431 """ 

432 plot_bkg(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None, new=True) 

433 

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

435 

436 Arguments 

437 ---------- 

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

439 norm bool whether to show normalized data [True] 

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

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

442 show_e0 bool whether to show E0 [False] 

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

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

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

446 

447 Notes 

448 ----- 

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

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

451 """ 

452 if hasattr(dgroup, 'mu'): 

453 mu = dgroup.mu 

454 elif hasattr(dgroup, 'mutrans'): 

455 mu = dgroup.mutrans 

456 else: 

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

458 

459 bkg = dgroup.bkg 

460 ylabel = plotlabels.mu 

461 if label is None: 

462 label = 'mu' 

463 

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

465 if norm: 

466 mu = dgroup.norm 

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

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

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

470 #endif 

471 title = _get_title(dgroup, title=title) 

472 

473 fig = PlotlyFigure(two_yaxis=False) 

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

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

476 

477 if show_e0: 

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

479 

480 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=ylabel, xmin=emin, xmax=emax) 

481 

482 

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

484 eweight=0, offset=0, how_k=False, fig=None, show=True): 

485 """ 

486 plot_chie(dgroup, emin=None, emax=None, label=None, new=True, fig=None): 

487 

488 Plot chi(E) for XAFS data group 

489 

490 Arguments 

491 ---------- 

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

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

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

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

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

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

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

499 show display the PlotlyFig now [True] 

500 fig PlotlyFigure to re-use [None] 

501 

502 Notes 

503 ----- 

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

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

506 """ 

507 if hasattr(dgroup, 'mu'): 

508 mu = dgroup.mu 

509 elif hasattr(dgroup, 'mutrans'): 

510 mu = dgroup.mutrans 

511 else: 

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

513 #endif 

514 e0 = dgroup.e0 

515 chie = (mu - dgroup.bkg) 

516 ylabel = plotlabels.chie 

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

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

519 ylabel = set_label_weight(plotlabels.chiew, eweight) 

520 xlabel = plotlabels.energy 

521 

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

523 if emin is not None: 

524 emin = emin - e0 

525 if emax is not None: 

526 emax = emax - e0 

527 

528 title = _get_title(dgroup, title=title) 

529 def ek_formatter(x, pos): 

530 ex = float(x) 

531 if ex < 0: 

532 s = '' 

533 else: 

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

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

536 

537 if fig is None: 

538 fig = PlotlyFigure(two_yaxis=False) 

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

540 return fig.show(title=title, xlabel=xlabel, ylabel=ylabel, xmin=emin, xmax=emax, show=show) 

541 

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

543 scale_window=True, label=None, title=None, offset=0, show=True, fig=None): 

544 """ 

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

546 fig=None) 

547 

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

549 

550 Arguments 

551 ---------- 

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

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

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

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

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

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

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

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

560 show display the PlotlyFig now [True] 

561 fig PlotlyFigure to re-use [None] 

562 

563 Notes 

564 ----- 

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

566 k, chi, kwin, filename 

567 """ 

568 kweight = _get_kweight(dgroup, kweight) 

569 chi = dgroup.chi * dgroup.k ** kweight 

570 

571 if label is None: 

572 label = 'chi' 

573 

574 title = _get_title(dgroup, title=title) 

575 

576 if fig is None: 

577 fig = PlotlyFigure(two_yaxis=False) 

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

579 

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

581 kwin = dgroup.kwin 

582 if scale_window: 

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

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

585 

586 return fig.show(title=title, xlabel=plotlabels.k, xmin=0, xmax=kmax, 

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

588 show=show) 

589 

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

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

592 offset=0, show=True, fig=None): 

593 """ 

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

595 rmax=None, label=None, fig=None) 

596 

597 Plot chi(R) for XAFS data group 

598 

599 Arguments 

600 ---------- 

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

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

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

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

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

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

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

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

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

610 show display the PlotlyFig now [True] 

611 fig PlotlyFigure to re-use [None] 

612 

613 Notes 

614 ----- 

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

616 r, chir_mag, chir_im, chir_re, kweight, filename 

617 """ 

618 kweight = _get_kweight(dgroup, None) 

619 

620 title = _get_title(dgroup, title=title) 

621 

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

623 show_real=show_real, show_imag=show_imag) 

624 

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

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

627 return 

628 #endif 

629 if label is None: 

630 label = 'chir' 

631 

632 if fig is None: 

633 fig = PlotlyFigure(two_yaxis=False) 

634 if show_mag: 

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

636 if show_real: 

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

638 

639 if show_imag: 

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

641 

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

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

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

645 

646 return fig.show(title=title, xlabel=plotlabels.r, ylabel=ylabel, xmax=rmax, show=show) 

647 

648 

649def plot_chiq(dgroup, kweight=None, kmin=0, kmax=None, show_chik=False, label=None, 

650 title=None, offset=0, show_window=False, scale_window=True, 

651 show=True, fig=None): 

652 """ 

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

654 new=True, win=1) 

655 

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

657 

658 Arguments 

659 ---------- 

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

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

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

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

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

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

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

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

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

669 show display the PlotlyFig now [True] 

670 fig PlotlyFigure to re-use [None] 

671 

672 Notes 

673 ----- 

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

675 k, chi, kwin, filename 

676 """ 

677 kweight = _get_kweight(dgroup, kweight) 

678 nk = len(dgroup.k) 

679 chiq = dgroup.chiq_re[:nk] 

680 

681 if label is None: 

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

683 

684 title = _get_title(dgroup, title=title) 

685 if fig is None: 

686 fig = PlotlyFigure(two_yaxis=False) 

687 fig.add_plot(dgroup.k, chiq+offset, label=label) 

688 if kmax is None: 

689 kmax = max(dgroup.k) 

690 

691 if show_chik: 

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

693 fig.add_plot(dgroup.k, chik+offset, label='chi(k) (unfiltered)') 

694 

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

696 kwin = dgroup.kwin 

697 if scale_window: 

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

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

700 

701 ylabel = set_label_weight(plotlabels.chikw, kweight) 

702 return fig.show(title=title, xlabel=plotlabels.k, 

703 ylabel=ylabel, xmin=kmin, xmax=kmax, show=show) 

704 

705 

706 

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

708 show_mag=True, show_real=False, show_imag=False, 

709 show_bkg=False, use_rebkg=False, title=None, offset=0): 

710 """ 

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

712 show_mag=True, show_real=False, show_imag=False) 

713 

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

715 

716 Arguments 

717 ---------- 

718 dataset feffit dataset, after running feffit() 

719 kmin min k to show [0] 

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

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

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

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

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

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

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

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

728 

729 

730 """ 

731 if kweight is None: 

732 kweight = dataset.transform.kweight 

733 #endif 

734 if isinstance(kweight, (list, tuple, np.ndarray)): 

735 kweight=kweight[0] 

736 

737 title = _get_title(dataset, title=title) 

738 

739 mod = dataset.model 

740 dat = dataset.data 

741 if use_rebkg and hasattr(dataset, 'data_rebkg'): 

742 dat = dataset.data_rebkg 

743 title += ' (refined bkg)' 

744 

745 data_chik = dat.chi * dat.k**kweight 

746 model_chik = mod.chi * mod.k**kweight 

747 

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

749 fig = PlotlyFigure(two_yaxis=False) 

750 fig.add_plot(dat.k, data_chik+offset, label='data') 

751 fig.add_plot(mod.k, model_chik+offset, label='fit') 

752 

753 ylabel = set_label_weight(plotlabels.chikw, kweight) 

754 fig.show(title=title, xlabel=plotlabels.k, 

755 ylabel=ylabel, xmin=kmin, xmax=kmax) 

756 

757 # chi(R) in first plot window 

758 rfig = PlotlyFigure(two_yaxis=False) 

759 

760 if show_mag: 

761 rfig.add_plot(dat.r, dat.chir_mag+offset, label='|data|') 

762 rfig.add_plot(mod.r, mod.chir_mag+offset, label='|fit|') 

763 

764 if show_real: 

765 rfig.add_plot(dat.r, dat.chir_re+offset, label='Re[data]') 

766 rfig.add_plot(mod.r, mod.chir_re+offset, label='Re[fit]') 

767 if show_imag: 

768 rfig.add_plot(dat.r, dat.chir_im+offset, label='Im[data]') 

769 rfig.add_plot(mod.r, mod.chir_im+offset, label='Im[fit]') 

770 

771 ylabel = chirlab(kweight, show_mag=show_mag, show_real=show_real, show_imag=show_imag) 

772 rfig.show(title=title, xlabel=plotlabels.r, ylabel=ylabel, xmin=0, xmax=rmax) 

773 return fig, rfig 

774 

775def plot_path_k(dataset, ipath=0, kmin=0, kmax=None, offset=0, label=None, fig=None): 

776 """ 

777 plot_path_k(dataset, ipath, kmin=0, kmax=None, offset=0, label=None) 

778 

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

780 

781 Arguments 

782 ---------- 

783 dataset feffit dataset, after running feffit() 

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

785 kmin min k to show [0] 

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

787 offset vertical offset to use for plot [0] 

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

789 fig PlotlyFigure for reuse 

790 """ 

791 kweight = dataset.transform.kweight 

792 path = dataset.pathlist[ipath] 

793 if label is None: 

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

795 title = _get_title(dataset, title=title) 

796 

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

798 if fig is None: 

799 fig = PlotlyFigure(two_yaxis=False) 

800 fig.add_plot(path.k, chi_kw, label=label) 

801 return fig.set_style(title=title, xlabel=plotlabels.k, 

802 yabel=set_label_weight(plotlabels.chikw, kweight), 

803 xmin=kmin, xmax=kmax) 

804 

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

806 show_mag=True, show_real=False, show_imag=True, fig=None): 

807 """ 

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

809 show_mag=True, show_real=False, show_imag=True, fig=None) 

810 

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

812 

813 Arguments 

814 ---------- 

815 dataset feffit dataset, after running feffit() 

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

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

818 offset vertical offset to use for plot [0] 

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

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

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

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

823 fig PlotlyFigure for reuse 

824 """ 

825 path = dataset.pathlist[ipath] 

826 if label is None: 

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

828 

829 title = _get_title(dataset, title=title) 

830 kweight =dataset.transform.kweight 

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

832 show_real=show_real, show_imag=show_imag) 

833 

834 if fig is None: 

835 fig = PlotlyFigure(two_yaxis=False) 

836 if show_mag: 

837 fig.add_plot(path.r, offset+path.chir_mag, label=f'|{label}|') 

838 

839 if show_real: 

840 fig.add_plot(path.r, offset+path.chir_re, label=f'Re[{label}|') 

841 

842 if show_imag: 

843 fig.add_plot(path.r, offset+path.chir_im, label=f'Im[{label}|') 

844 

845 return fig.show(title=title, xlabel=plotlabels.r, ylabel=chirlab(kweight), 

846 xmax=rmax) 

847 

848 

849def plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, title=None, fig=None): 

850 """ 

851 plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, fig=None) 

852 

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

854 

855 Arguments 

856 ---------- 

857 dataset feffit dataset, after running feffit() 

858 kmin min k to show [0] 

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

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

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

862 fig PlotlyFigure for reuse 

863 """ 

864 # make k-weighted chi(k) 

865 kweight = dataset.transform.kweight 

866 model = dataset.model 

867 

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

869 

870 title = _get_title(dataset, title=title) 

871 if fig is None: 

872 fig = PlotlyFigure(two_yaxis=False) 

873 fig.add_plot(model.k, model_chi_kw, label='sum') 

874 

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

876 path = dataset.pathlist[ipath] 

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

878 chi_kw = offset*(1+ipath) + path.chi * path.k**kweight 

879 fig.add_plot(path.k, chi_kw, label=label) 

880 

881 return fig.show(title=title, xlabel=plotlabels.k, 

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

883 xmin=kmin, xmax=kmax) 

884 

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

886 show_real=False, show_imag=False, title=None, fig=None): 

887 """ 

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

889 show_imag=False) 

890 

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

892 

893 Arguments 

894 ---------- 

895 dataset feffit dataset, after running feffit() 

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

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

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

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

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

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

902 fig PlotlyFigure for reuse 

903 """ 

904 kweight = dataset.transform.kweight 

905 model = dataset.model 

906 

907 title = _get_title(dataset, title=title) 

908 if fig is None: 

909 fig = PlotlyFigure(two_yaxis=False) 

910 

911 if show_mag: 

912 fig.add_plot(model.r, model.chir_mag, label='|sum|') 

913 

914 if show_real: 

915 fig.add_plot(model.r, model.chir_re, label='Re[sum]') 

916 

917 if show_imag: 

918 fig.add_plot(model.r, model.chir_re, label='Im[sum]') 

919 

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

921 path = dataset.pathlist[ipath] 

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

923 off = (ipath+1)*offset 

924 if show_mag: 

925 fig.add_plot(path.r, off+path.chir_mag, label=f'|{label}|') 

926 

927 if show_real: 

928 fig.add_plot(path.r, off+path.chir_re, label=f'Re[{label}]') 

929 

930 if show_imag: 

931 fig.add_plot(path.r, off+path.chir_im, label=f'Im[{label}]') 

932 

933 return fig.show(title=title, xlabel=plotlabels.r, 

934 ylabel=chirlab(kweight), xmax=rmax) 

935 

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

937 show_peakrange=True): 

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

939 

940 dgroup must have a 'prepeaks' attribute 

941 """ 

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

943 raise ValueError('Group needs prepeaks') 

944 #endif 

945 ppeak = dgroup.prepeaks 

946 

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

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

949 

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

951 

952 fig = PlotlyFigure(two_yaxis=False) 

953 

954 ydat = dgroup.ydat 

955 xdat = dgroup.xdat 

956 if subtract_baseline: 

957 fig.add_plot(ppeak.energy, ppeak.baseline, label='baseline subtracted peaks') 

958 else: 

959 fig.add_plot(ppeak.energy, ppeak.baseline, label='baseline') 

960 fig.add_plot(xdat, ydat, label='data') 

961 

962 if show_fitrange: 

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

964 fig.add_vline(x=x, line_width=2, line_dash="dash", line_color="#DDDDCC") 

965 fig.add_vline(x=ppeak.centroid, line_width=2, line_dash="dash", line_color="#EECCCC") 

966 

967 if show_peakrange: 

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

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

970 fig.add_plot([x], [y], marker='o', marker_size=7) 

971 

972 return fig.show(title=title, xlabel=plotlabels.energy, ylabel='mu (normalized)', 

973 xmin=px0, xmax=px1, ymin=py0, ymax=py1) 

974 

975 

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

977 show_residual=False): 

978 """plot pre-edge peak fit, as from Larix 

979 

980 dgroup must have a 'peakfit_history' attribute 

981 """ 

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

983 raise ValueError('Group needs prepeaks') 

984 #endif 

985 if show_init: 

986 result = pkfit = dgroup.prepeaks 

987 else: 

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

989 if nfit > len(hist): 

990 nfit = 0 

991 pkfit = hist[nfit] 

992 result = pkfit.result 

993 #endif 

994 

995 if pkfit is None: 

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

997 #endif 

998 

999 opts = pkfit.user_options 

1000 xeps = min(np.diff(dgroup.xdat)) / 5. 

1001 xdat = 1.0*pkfit.energy 

1002 ydat = 1.0*pkfit.norm 

1003 

1004 xdat_full = 1.0*dgroup.xdat 

1005 ydat_full = 1.0*dgroup.ydat 

1006 

1007 if show_init: 

1008 yfit = pkfit.init_fit 

1009 ycomps = None # pkfit.init_ycomps 

1010 ylabel = 'model' 

1011 else: 

1012 yfit = 1.0*result.best_fit 

1013 ycomps = pkfit.ycomps 

1014 ylabel = 'best fit' 

1015 

1016 baseline = 0.*ydat 

1017 if ycomps is not None: 

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

1019 if label in opts['bkg_components']: 

1020 baseline += ycomp 

1021 

1022 fig = PlotlyFigure(two_yaxis=False) 

1023 title ='%s:\npre-edge peak' % dgroup.filename 

1024 

1025 

1026 

1027 if subtract_baseline: 

1028 ydat -= baseline 

1029 yfit -= baseline 

1030 ydat_full = 1.0*ydat 

1031 xdat_full = 1.0*xdat 

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

1033 

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

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

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

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

1038 

1039 ncolor = 0 

1040 popts = {} 

1041 plotopts.update(popts) 

1042 dymin = dymax = None 

1043 

1044 fig.add_plot(xdat, ydat, label='data') 

1045 fig.add_plot(xday, yfit, label='fit') 

1046 

1047 if show_residual: 

1048 dfig = PlotlyFigure() 

1049 dfig.add_plot(xdat, yfit-ydat, label='fit-data') 

1050 dy = yfit - ydat 

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

1052 dymax += 0.05 * (dymax - dymin) 

1053 dymin -= 0.05 * (dymax - dymin) 

1054 

1055 if ycomps is not None: 

1056 ncomps = len(ycomps) 

1057 if not subtract_baseline: 

1058 fig.add_plot(xdat, baseline, label='baseline') 

1059 for icomp, label in enumerate(ycomps): 

1060 ycomp = ycomps[label] 

1061 if label in opts['bkg_components']: 

1062 continue 

1063 fig.add_plot(xdat, ycomp, label=label) 

1064 

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

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

1067 fig.add_vline(opts[attr], line_width=2, line_dash="dash", line_color="#DDDDCC") 

1068 

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

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

1071 if hasattr(result, 'params'): 

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

1073 if pcen is not None: 

1074 pcen = pcen.value 

1075 if pcen is not None: 

1076 fig.add_vlinee(pcen, color='#EECCCC') 

1077 

1078 fig.show(title=title, xlabel=plotlabels.energy, ylabel=opts['array_desc']) 

1079 dfig.show(title=tile, ylabel='fit-data', ymin=dymin, ymax=dymax) 

1080 return fig, dfig 

1081 

1082 

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

1084 if ncomps is None: 

1085 if min_weight > 1.e-12: 

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

1087 else: 

1088 ncomps = np.argmin(result.ind) 

1089 return ncomps 

1090 

1091 

1092def plot_pca_components(result, min_weight=0, ncomps=None, min_variance=1.e-5): 

1093 """Plot components from PCA result 

1094 

1095 result must be output of `pca_train` 

1096 """ 

1097 title = "PCA components" 

1098 

1099 ncomps = int(result.nsig) 

1100 fig = PlotlyFigure(two_yaxis=False) 

1101 fig.add_plot(result.x, result.mean, label='Mean') 

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

1103 if result.variances[i] > min_variance: 

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

1105 fig.add_plot(result.x, comp, label=label) 

1106 

1107 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=plotlabels.norm, 

1108 xmin=result.xmin, xmax=result.xmax) 

1109 

1110def plot_pca_weights(result, min_weight=0, ncomps=None): 

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

1112 

1113 result must be output of `pca_train` 

1114 """ 

1115 max_comps = len(result.components)-1 

1116 

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

1118 fig = PlotlyFigure(two_yaxis=True) 

1119 

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

1121 

1122 x0, x1, y0, y1 = extend_plotrange(result.variances, result.variances) 

1123 y0 = max(1.e-6, min(result.variances[:-1])) 

1124 x = 1+np.arange(ncomps) 

1125 y = result.variances[:ncomps] 

1126 fig.add_plot(x, y, label='significant', style='solid', marker='o') 

1127 

1128 xe = 1 + np.arange(ncomps-1, max_comps) 

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

1130 

1131 fig.add_plot(xe, ye, label='not significant', style='dashed', marker='o') 

1132 fig.set_ylog() 

1133 yi = result.ind[1:] 

1134 xi = 1 + np.arange(len(yi)) 

1135 

1136 x0, x1, yimin, yimax = extend_plotrange(xi, yi) 

1137 

1138 fig.add_plot(xi, result.ind[1:], label='Indicator Value', 

1139 style='solid', side='right') 

1140 fig.fig.update_yaxes(title_text='Indicator', secondary_y=True) 

1141 return fig.show(title=title, xlabel='Component #', ylabel='variance') 

1142 

1143 

1144def plot_pca_fit(dgroup, with_components=True): 

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

1146 

1147 result must be output of `pca_fit` 

1148 """ 

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

1150 result = dgroup.pca_result 

1151 model = result.pca_model 

1152 

1153 fig = PlotlyFigure(two_yaxis=False) 

1154 fig.add_plot(result.x, result.ydat, label='data') 

1155 fig.add_plot(result.x, result.yfit, label='fit') 

1156 if with_components: 

1157 fig.add_plot(result.x, model.mean, label='mean') 

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

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

1160 fig.add_plot(result.x, cval, label='Comp #%d' % (n+1)) 

1161 

1162 fig.show(title=title, xmin=model.xmin, xmax=model.xmax, 

1163 xlabel=plotlabels.energy, ylabel=plotlabels.norm) 

1164 

1165 dfig = PlotlyFigure(two_yaxis=False) 

1166 dfig.add_plot(result.x, result.yfit-result.ydat, label='fit-data') 

1167 dfig.show(title=title, xmin=model.xmin, xmax=model.xmax, 

1168 xlabel=plotlabels.energy, ylabel='fit-data') 

1169 return fig, dfig 

1170 

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

1172 title=None, offset=0): 

1173 """ 

1174 plot_diffkk(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None): 

1175 

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

1177 

1178 Arguments 

1179 ---------- 

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

1181 norm bool whether to show normalized data [True] 

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

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

1184 show_e0 bool whether to show E0 [False] 

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

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

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

1188 

1189 Notes 

1190 ----- 

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

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

1193 """ 

1194 if hasattr(dgroup, 'f2'): 

1195 f2 = dgroup.f2 

1196 else: 

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

1198 #endif 

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

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

1201 title = _get_title(dgroup, title=title) 

1202 

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

1204 

1205 fig = PlotlyFigure(two_yaxis=False) 

1206 fig.add_plot(dgroup.energy, f2, label=labels['f2']) 

1207 

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

1209 yval = getattr(dgroup, attr) 

1210 if yval is not None: 

1211 fig.add_plot(dgroup.energy, yval, label=labels[attr]) 

1212 

1213 return fig.show(title=title, xlabel=plotlabels.energy, yaxis_label=ylabel, 

1214 xmin=emin, xmax=emax) 

1215 

1216 

1217def plot_feffdat(feffpath, with_phase=True, title=None, fig=None): 

1218 """ 

1219 plot_feffdat(feffpath, with_phase=True, title=None) 

1220 

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

1222 

1223 Arguments 

1224 ---------- 

1225 feffpath feff path as read by feffpath() 

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

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

1228 

1229 Notes 

1230 ----- 

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

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

1233 """ 

1234 if hasattr(feffpath, '_feffdat'): 

1235 fdat = feffpath._feffdat 

1236 else: 

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

1238 

1239 if fig is None: 

1240 fig = PlotlyFigure(two_yaxis=True) 

1241 fig.add_plot(result.x, result.ydat, label='data') 

1242 

1243 

1244 fig.add_plot(fdat.k, fdat.mag_feff, label='magnitude') 

1245 # xlabel=plotlabels.k, 

1246 # ylabel='|F(k)|', title=title, 

1247 

1248 if with_phase: 

1249 fig.add_plot(fdat.k, fdat.pha_feff, label='phase') 

1250 fig.fig.update_yaxis(title_text='Phase(k)', secondary_y=True) 

1251 return fig.show(title=title, xlabel=plotlabels.k, ylabel='|F(k)|') 

1252 

1253#enddef 

1254 

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

1256 rmax=None, kmax=None, kweight=None, title=None): 

1257 """ 

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

1259 rmax=None, kmax=None, kweight=None, title=None) 

1260 

1261 Plot wavelet for XAFS data group 

1262 

1263 Arguments 

1264 ---------- 

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

1266 show_mag bool whether to plot wavelet magnitude [True] 

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

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

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

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

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

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

1273 

1274 Notes 

1275 ----- 

1276 The wavelet will be performed 

1277 """ 

1278 print("Image display not yet available with larch+plotly") 

1279 kweight = _get_kweight(dgroup, kweight) 

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

1281 title = _get_title(dgroup, title=title) 

1282 

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

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

1285 show_axis=True) 

1286 if show_mag: 

1287 _imshow(dgroup.wcauchy_mag, **opts) 

1288 elif show_real: 

1289 _imshow(dgroup.wcauchy_real, **opts) 

1290 elif show_imag: 

1291 _imshow(dgroup.wcauchy_imag, **opts) 

1292 #endif 

1293#enddef