Coverage for larch/plot/bokeh_xafsplots.py: 0%
667 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-10-16 21:04 +0000
« 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
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"""
21import os
22import numpy as np
23import time
24import logging
25from copy import deepcopy
27from larch import Group
28from larch.math import index_of
29from larch.xafs import cauchy_wavelet, etok
31def nullfunc(*args, **kws):
32 pass
34get_display = _plot = _oplot = _newplot = _fitplot = _plot_text = nullfunc
36HAS_BOKEH = True
37try:
38 import bokeh
39except ImportError:
40 HAS_BOKEH = False
42if HAS_BOKEH:
43 from bokeh import plotting as bplot
44 from bokeh.plotting import figure, show
45 from bokeh.io import output_notebook, curdoc
46 from bokeh.io import show as bokeh_show
48 from bokeh.core.properties import field
49 from bokeh.models import ColumnDataSource, LinearAxis, Grid, VSpan, Range1d
53LineColors = ('#1f77b4', '#d62728', '#2ca02c', '#ff7f0e', '#9467bd',
54 '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf')
55LineStyles = ('solid', 'dashed', 'dotted')
56NCOLORS = len(LineColors)
57NSTYLES = len(LineStyles)
59FIGSTYLE = dict(width=800, height=500,
60 toolbar_location='above',
61 tools="pan,box_zoom,save,reset",
63 # showlegend=True, hovermode='closest',
64 # legend=dict(borderwidth=0.5, bgcolor='#F2F2F2'),
65 # # orientation='v') #, x=0.1, y=1.15)# , yanchor='top'),
66 #plot_bgcolor='#FDFDFF',
67 #xaxis=dict(showgrid=True, gridcolor='#D8D8D8',
68 # color='#004', zerolinecolor='#DDD'),
69 #
70 # yaxis=dict(showgrid=True, gridcolor='#D8D8D8',
71 # color='#004', zerolinecolor='#DDD')
72 )
74def set_label_weight(label, w):
75 return label.replace('_w_', '{0:g}'.format(w))
77# common XAFS plot labels
78def chirlab(kweight, show_mag=True, show_real=False, show_imag=False):
79 """generate chi(R) label for a kweight
81 Arguments
82 ----------
83 kweight k-weight to use (required)
84 show_mag bool whether to plot |chi(R)| [True]
85 show_real bool whether to plot Re[chi(R)] [False]
86 show_imag bool whether to plot Im[chi(R)] [False]
87 """
88 ylab = []
89 if show_mag: ylab.append(plotlabels.chirmag)
90 if show_real: ylab.append(plotlabels.chirre)
91 if show_imag: ylab.append(plotlabels.chirim)
92 if len(ylab) > 1: ylab = [plotlabels.chir]
93 return set_label_weight(ylab[0], kweight+1)
94#enddef
96# note:
97# to make life easier for MathJax/Plotly/Bokeh/IPython
98# we have just replaced "\AA" with "\unicode{x212B}"
100plotlabels = Group(k = r'$$k \rm\,(\unicode{x212B}^{-1})$$',
101 r = r'$$R \rm\,(\unicode{x212B})$$',
102 energy = r'$$E\rm\,(eV)$$',
103 ewithk = r'$$E\rm\,(eV)$$' + '\n' + r'$$[k \rm\,(\unicode{x212B}^{-1})]$$',
104 mu = r'$$\mu(E)$$',
105 norm = r'normalized $$\mu(E)$$',
106 flat = r'flattened $$\mu(E)$$',
107 deconv = r'deconvolved $$\mu(E)$$',
108 dmude = r'$$d\mu_{\mathrm norm}(E)/dE$$',
109 d2mude = r'$$d^2\mu_{\rm norm}(E)/dE^2$$',
110 chie = r'$$\chi(E)$$',
111 chie0 = r'$$\chi(E)$$',
112 chie1 = r'$$E\chi(E) \rm\, (eV)$$',
113 chiew = r'$$E^{{_w_}\chi(E) \rm\,(eV^{_w_})$$',
114 chikw = r'$$k^{{_w_}}\chi(k) \rm\,(\unicode{x212B}^{{-_w_}})$$',
115 chi0 = r'$$\chi(k)$$',
116 chi1 = r'$$k\chi(k) \rm\,(\unicode{x212B}^{-1})$$',
117 chi2 = r'$$k^2\chi(k) \rm\,(\unicode{x212B}^{-2})$$',
118 chi3 = r'$$k^3\chi(k) \rm\,(\unicode{x212B}^{-3})$$',
119 chir = r'$$\chi(R) \rm\,(\unicode{x212B}^{{-_w_}})$$',
120 chirmag = r'$$|\chi(R)| \rm\,(\unicode{x212B}^{{-_w_}})$$',
121 chirre = r'$${{\rm Re}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$$',
122 chirim = r'$${{\rm Im}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$$',
123 chirpha = r'$${{\rm Phase}}[\chi(R)] \rm\,(\unicode{x212B}^{{-_w_}})$$',
124 e0color = '#B2B282',
125 chirlab = chirlab)
128def safetitle(t):
129 if "'" in t:
130 t = t.replace("'", "\\'")
131 return t
133def _get_title(dgroup, title=None):
134 """get best title for group"""
135 if title is not None:
136 return safetitle(title)
137 data_group = getattr(dgroup, 'data', None)
139 for attr in ('title', 'plot_title', 'filename', 'name', '__name__'):
140 t = getattr(dgroup, attr, None)
141 if t is not None:
142 if attr == 'filename':
143 folder, file = os.path.split(t)
144 if folder == '':
145 t = file
146 else:
147 top, folder = os.path.split(folder)
148 t = '/'.join((folder, file))
149 return safetitle(t)
150 if data_group is not None:
151 t = getattr(data_group, attr, None)
152 if t is not None:
153 return t
154 return safetitle(repr(dgroup))
157def _get_kweight(dgroup, kweight=None):
158 if kweight is not None:
159 return kweight
160 callargs = getattr(dgroup, 'callargs', None)
161 ftargs = getattr(callargs, 'xftf', {'kweight':0})
162 return ftargs['kweight']
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
184def extend_plotrange(x, y, xmin=None, xmax=None, extend=0.10):
185 """return plot limits to extend a plot range for x, y pairs"""
186 xeps = min(np.diff(x)) / 5.
187 if xmin is None:
188 xmin = min(x)
189 if xmax is None:
190 xmax = max(x)
192 xmin = max(min(x), xmin-5)
193 xmax = min(max(x), xmax+5)
195 i0 = index_of(x, xmin + xeps)
196 i1 = index_of(x, xmax + xeps) + 1
198 xspan = x[i0:i1]
199 xrange = max(xspan) - min(xspan)
200 yspan = y[i0:i1]
201 yrange = max(yspan) - min(yspan)
203 return (min(xspan) - extend * xrange,
204 max(xspan) + extend * xrange,
205 min(yspan) - extend * yrange,
206 max(yspan) + extend * yrange)
209def redraw(win=1, xmin=None, xmax=None, ymin=None, ymax=None,
210 dymin=None, dymax=None,
211 show_legend=True, stacked=False):
212 pass
215class BokehFigure:
216 """wrapping of Bokeh Figure
217 """
218 def __init__(self, style=None, **kws):
220 try:
221 self.in_ipython = __IPYTHON__
222 except NameError:
223 self.in_ipython = False
224 if self.in_ipython:
225 output_notebook()
226 style = self.style = deepcopy(FIGSTYLE)
227 if style is not None:
228 self.style.update(style)
231 self.fig = bplot.figure(width=style['width'], height=style['height'],
232 toolbar_location=style['toolbar_location'],
233 tools=style['tools'])
235 self.fig.xgrid.grid_line_color = '#D8D8D8'
236 self.fig.ygrid.grid_line_color = '#D8D8D8'
237 self.fig.legend.click_policy = 'hide'
238 self.fig
239 self.clear()
242 def clear(self):
243 self.y2_axes = None
244 self.traces = []
246 def add_plot(self, x, y, label=None, color=None, linewidth=3,
247 style='solid', marker=None, y2label=None, side='left'):
248 itrace = len(self.traces)
250 if label is None:
251 label = "trace %d" % (1+itrace)
252 if color is None:
253 color = LineColors[itrace % NCOLORS]
254 if style is None:
255 style = LineStyles[ int(itrace*1.0 / NCOLORS) % NSTYLES]
257 opts = {'line_color': color, 'line_width': linewidth,
258 'legend_label': label}
260 if side == 'right':
261 if y2label is None:
262 y2label = label
264 ymin, ymax = min(y), max(y)
265 yr = abs(ymax-ymin)
266 try:
267 if yr/(ymin+ymax) > 1.e-18:
268 ymin, ymax = ymin-0.02*yr, ymax+0.02*yr
269 except:
270 pass
271 self.fig.extra_y_ranges['y2'] = Range1d(ymin, ymax)
272 self.y2_axes = LinearAxis(axis_label=y2label, y_range_name='y2')
274 self.fig.add_layout(self.y2_axes, 'left')
275 opts['y_range_name'] = 'y2'
277 trace = self.fig.line(x, y, **opts)
278 self.traces.append((trace, x, y, opts))
279 self.fig.legend.click_policy='hide'
281 def add_vline(self, x=None, line_width=1, line_color='#666666', **kws):
282 if x is None:
283 return
285 source = ColumnDataSource({'x': [x], 'y': [line_width]})
286 glyph = VSpan(x=x, line_width=line_width, line_color=line_color)
287 self.fig.add_glyph(source, glyph)
289 def set_xrange(self, xmin, xmax):
291 if xmin is not None:
292 self.fig.x_range.start = xmin
293 if xmax is not None:
294 self.fig.x_range.end = xmax
297 def set_yrange(self, ymin, ymax):
298 if ymin is not None:
299 self.fig.y_range.start = ymin
300 if ymax is not None:
301 self.fig.y_range.end = ymax
304 def set_ylog(self, ylog=True):
305 ytype = 'log' if ylog else 'linear'
306 self.fig.y_axis_type = ytype
309 def set_style(self, title=None, xlabel=None, ylabel=None, y2label=None):
310 if title is not None:
311 self.fig.title.text = title
312 if xlabel is not None:
313 self.fig.xaxis.axis_label = xlabel
314 if ylabel is not None:
315 self.fig.yaxis.axis_label = ylabel
316 if y2label is not None and self.y2_axes is not None:
317 self.y2_axes.axis_label = y2label
320 def show(self, title=None, xlabel=None, ylabel=None, y2label=None,
321 xmin=None, xmax=None, ymin=None, ymax=None, show=True):
322 self.set_style(title=title, xlabel=xlabel, ylabel=ylabel, y2label=y2label)
323 self.set_xrange(xmin, xmax)
324 self.set_yrange(ymin, ymax)
326 if show:
327 curdoc().add_root(self.fig)
328 bokeh_show(self.fig)
329 return self
331def plot(xdata, ydata, dy=None, fig=None, label=None, xlabel=None,
332 ylabel=None, y2label=None, title=None, side='left', ylog_scale=None,
333 xlog_scale=None, grid=None, xmin=None, xmax=None, ymin=None,
334 ymax=None, color=None, style='solid', alpha=None, fill=False,
335 drawstyle=None, linewidth=2, marker=None, markersize=None,
336 show_legend=None, bgcolor=None, framecolor=None, gridcolor=None,
337 textcolor=None, labelfontsize=None, titlefontsize=None,
338 legendfontsize=None, fullbox=None, axes_style=None, zorder=None, show=True):
339 """emulate wxmplot plot() function, probably incompletely"""
341 if fig is None:
342 fig = BokehFigure()
344 if xmin is None:
345 xmin = min(xdata)
346 if xmax is None:
347 xmax = max(xdata)
348 if ymin is None:
349 ymin = min(ydata)
350 if ymax is None:
351 ymax = max(ydata)
353 if xmin is not None and xmax is not None:
354 xr = abs(xmax-xmin)
355 try:
356 if xr/(xmin+xmax) > 1.e-18:
357 xmin, xmax = xmin-0.02*xr, xmax+0.02*xr
358 except:
359 pass
360 if ymin is not None and ymay is not None:
361 yr = abs(ymax-ymin)
362 try:
363 if yr/(ymin+ymax) > 1.e-18:
364 ymin, ymax = ymin-0.02*yr, ymax+0.02*yr
365 except:
366 pass
368 fig.add_plot(xdata, ydata, label=label, color=color, linewidth=linewidth,
369 style=style, marker=marker, side=side)
371 return fig.show(title=title, xlabel=xlabel, ylabel=ylabel, y2label=y2label,
372 xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, show=show)
375def multi_plot(plotsets):
376 """plot multiple traces with an array of dictionaries emulating
377 multiplot calls to plot:
379 instead of
381 >>> plot(x1, y1, label='thing1', color='blue')
382 >>> plot(x2, y2, label='thing2', color='red')
384 you can do
386 >>> multi_plot([dict(xdata=x1, ydata=y1, label='thing1', color='blue'),
387 dict(xdata=x2, ydata=y2, label='thing2', color='red')])
389 """
390 for pset in plotsets[:]:
391 side = pset.get('side', None)
392 fig = BokehFigure()
393 fig.clear()
395 sopts = dict(title=None, xlabel=None, ylabel=None)
396 ropts = dict(xmin=None, xmax=None, ymin=None, ymax=None)
398 for pset in plotsets[:]:
399 xdata = pset['xdata']
400 ydata = pset['ydata']
401 popts = dict(label=None, color=None, side='left', style=None,
402 linewidth=3, marker=None)
403 for w in ('label', 'color', 'style', 'linewidth', 'marker', 'side'):
404 if w in pset:
405 popts[w] = pset[w]
406 for w in ('title', 'xlabel', 'ylabel'):
407 if w in pset:
408 sopts[w] = pset[w]
410 for w in ('xmin', 'xmax', 'ymin', 'ymax'):
411 if w in pset:
412 ropts[w] = pset[w]
414 fig.add_plot(xdata, ydata, **popts)
416 sopts['xaxis_title'] = sopts.pop('xlabel')
417 sopts['yaxis_title'] = sopts.pop('ylabel')
418 fig.style.update(sopts)
419 return fig.show(**ropts)
421def plot_mu(dgroup, show_norm=False, show_flat=False, show_deriv=False,
422 show_pre=False, show_post=False, show_e0=False, with_deriv=False,
423 emin=None, emax=None, label='mu', offset=0, title=None, fig=None, show=True):
424 """
425 plot_mu(dgroup, norm=False, deriv=False, show_pre=False, show_post=False,
426 show_e0=False, show_deriv=False, emin=None, emax=None, label=None,
427 show=True, fig=None)
429 Plot mu(E) for an XAFS data group in various forms
431 Arplguments
432 ----------
433 dgroup group of XAFS data after pre_edge() results (see Note 1)
434 show_norm bool whether to show normalized data [False]
435 show_flat bool whether to show flattened, normalized data [False]
436 show_deriv bool whether to show derivative of normalized data [False]
437 show_pre bool whether to show pre-edge curve [False]
438 show_post bool whether to show post-edge curve [False]
439 show_e0 bool whether to show E0 [False]
440 with_deriv bool whether to show deriv (dmu/de) together with mu [False]
441 emin min energy to show, absolute or relative to E0 [None, start of data]
442 emax max energy to show, absolute or relative to E0 [None, end of data]
443 label string for label [None: 'mu', `dmu/dE', or 'mu norm']
444 title string for plot title [None, may use filename if available]
445 offset vertical offset to use for y-array [0]
446 show display the BokehFig now [True]
447 fig BokehFig to reuse [None]
449 Notes
450 -----
451 1. The input data group must have the following attributes:
452 energy, mu, norm, e0, pre_edge, edge_step
453 """
454 if not HAS_BOKEH:
455 logging.getLogger().error('Need bokeh installed')
456 return
458 if hasattr(dgroup, 'mu'):
459 mu = dgroup.mu
460 elif hasattr(dgroup, 'mutrans'):
461 mu = dgroup.mutrans
462 elif hasattr(dgroup, 'mufluor'):
463 mu = dgroup.mufluor
464 else:
465 raise ValueError("XAFS data group has no array for mu")
466 #endif
467 ylabel = plotlabels.mu
468 if label is None:
469 label = getattr(dgroup, 'filename', 'mu')
470 #endif
471 if show_deriv:
472 mu = dgroup.dmude
473 ylabel = f"{ylabel} (deriv)"
474 dlabel = plotlabels.dmude
475 elif show_norm:
476 mu = dgroup.norm
477 ylabel = plotlabels.norm
478 dlabel = plotlabels.norm
479 #endif
480 elif show_flat:
481 mu = dgroup.flat
482 ylabel = f"{ylabel} (flat)"
483 dlabel = plotlabels.flat
484 #endif
485 emin, emax = _get_erange(dgroup, emin, emax)
486 title = _get_title(dgroup, title=title)
488 if fig is None:
489 fig = BokehFigure()
490 fig.add_plot(dgroup.energy, mu+offset, label=label)
492 y2label = None
493 if with_deriv:
494 y2label = plotlabels.dmude
495 fig.add_plot(dgroup.energy, dgroup.dmude+offset, label=ylabel, y2label=y2label, side='right')
496 else:
497 if not show_norm and show_pre:
498 fig.add_plot(dgroup.energy, dgroup.pre_edge+offset, label='pre_edge')
499 if not show_norm and show_post:
500 fig.add_plot(dgroup.energy, dgroup.post_edge+offset, label='post_edge')
502 if show_e0:
503 fig.add_vline(x=dgroup.e0, line_width=2, line_dash="dash", line_color="#AAC")
505 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=ylabel,
506 y2label=y2label, xmin=emin, xmax=emax, show=show)
509def plot_bkg(dgroup, norm=True, emin=None, emax=None, show_e0=False,
510 label=None, title=None, offset=0):
511 """
512 plot_bkg(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None, new=True)
514 Plot mu(E) and background mu0(E) for XAFS data group
516 Arguments
517 ----------
518 dgroup group of XAFS data after autobk() results (see Note 1)
519 norm bool whether to show normalized data [True]
520 emin min energy to show, absolute or relative to E0 [None, start of data]
521 emax max energy to show, absolute or relative to E0 [None, end of data]
522 show_e0 bool whether to show E0 [False]
523 label string for label [``None``: 'mu']
524 title string for plot titlte [None, may use filename if available]
525 offset vertical offset to use for y-array [0]
527 Notes
528 -----
529 1. The input data group must have the following attributes:
530 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename
531 """
532 if hasattr(dgroup, 'mu'):
533 mu = dgroup.mu
534 elif hasattr(dgroup, 'mutrans'):
535 mu = dgroup.mutrans
536 else:
537 raise ValueError("XAFS data group has no array for mu")
539 bkg = dgroup.bkg
540 ylabel = plotlabels.mu
541 if label is None:
542 label = 'mu'
544 emin, emax = _get_erange(dgroup, emin, emax)
545 if norm:
546 mu = dgroup.norm
547 bkg = (dgroup.bkg - dgroup.pre_edge) / dgroup.edge_step
548 ylabel = plotlabels.norm
549 label = ylabel
550 #endif
551 title = _get_title(dgroup, title=title)
553 fig = BokehFigure()
554 fig.add_plot(dgroup.energy, mu+offset, label=label)
555 fig.add_plot(dgroup.energy, bkg+offset, label='bkg')
557 if show_e0:
558 fig.add_vline(x=dgroup.e0, line_width=2, line_dash="dash", line_color="#AAC")
560 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=ylabel, xmin=emin, xmax=emax)
563def plot_chie(dgroup, emin=-5, emax=None, label=None, title=None,
564 eweight=0, offset=0, how_k=False, fig=None, show=True):
565 """
566 plot_chie(dgroup, emin=None, emax=None, label=None, new=True, fig=None):
568 Plot chi(E) for XAFS data group
570 Arguments
571 ----------
572 dgroup group of XAFS data after autobk() results (see Note 1)
573 emin min energy to show, absolute or relative to E0 [-25]
574 emax max energy to show, absolute or relative to E0 [None, end of data]
575 label string for label [``None``: 'mu']
576 title string for plot title [None, may use filename if available]
577 eweight energy weightingn for energisdef es>e0 [0]
578 offset vertical offset to use for y-array [0]
579 show display the BokehFigure now [True]
580 fig BokehFigure to re-use [None]
582 Notes
583 -----
584 1. The input data group must have the following attributes:
585 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename
586 """
587 if hasattr(dgroup, 'mu'):
588 mu = dgroup.mu
589 elif hasattr(dgroup, 'mutrans'):
590 mu = dgroup.mutrans
591 else:
592 raise ValueError("XAFS data group has no array for mu")
593 #endif
594 e0 = dgroup.e0
595 chie = (mu - dgroup.bkg)
596 ylabel = plotlabels.chie
597 if abs(eweight) > 1.e-2:
598 chie *= (dgroup.energy-e0)**(eweight)
599 ylabel = set_label_weight(plotlabels.chiew, eweight)
600 xlabel = plotlabels.energy
602 emin, emax = _get_erange(dgroup, emin, emax)
603 if emin is not None:
604 emin = emin - e0
605 if emax is not None:
606 emax = emax - e0
608 title = _get_title(dgroup, title=title)
609 def ek_formatter(x, pos):
610 ex = float(x)
611 if ex < 0:
612 s = ''
613 else:
614 s = f"\n[{etok(ex):.2f}]"
615 return r"%1.4g%s" % (x, s)
617 if fig is None:
618 fig = BokehFigure()
619 fig.add_plot(dgroup.energy-e0, chie+offset, label=label)
620 return fig.show(title=title, xlabel=xlabel, ylabel=ylabel, xmin=emin, xmax=emax, show=show)
622def plot_chik(dgroup, kweight=None, kmax=None, show_window=True,
623 scale_window=True, label=None, title=None, offset=0, show=True, fig=None):
624 """
625 plot_chik(dgroup, kweight=None, kmax=None, show_window=True, label=None,
626 fig=None)
628 Plot k-weighted chi(k) for XAFS data group
630 Arguments
631 ----------
632 dgroup group of XAFS data after autobk() results (see Note 1)
633 kweight k-weighting for plot [read from last xftf(), or 0]
634 kmax max k to show [None, end of data]
635 show_window bool whether to also plot k-window [True]
636 scale_window bool whether to scale k-window to max |chi(k)| [True]
637 label string for label [``None`` to use 'chi']
638 title string for plot title [None, may use filename if available]
639 offset vertical offset to use for y-array [0]
640 show display the BokehFig now [True]
641 fig BokehFigure to re-use [None]
643 Notes
644 -----
645 1. The input data group must have the following attributes:
646 k, chi, kwin, filename
647 """
648 kweight = _get_kweight(dgroup, kweight)
649 chi = dgroup.chi * dgroup.k ** kweight
651 if label is None:
652 label = 'chi'
654 title = _get_title(dgroup, title=title)
656 if fig is None:
657 fig = BokehFigure()
658 fig.add_plot(dgroup.k, chi+offset, label=label)
660 if show_window and hasattr(dgroup, 'kwin'):
661 kwin = dgroup.kwin
662 if scale_window:
663 kwin = kwin*max(abs(chi))
664 fig.add_plot(dgroup.k, kwin+offset, label='window')
666 return fig.show(title=title, xlabel=plotlabels.k, xmin=0, xmax=kmax,
667 ylabel=set_label_weight(plotlabels.chikw, kweight),
668 show=show)
670def plot_chir(dgroup, show_mag=True, show_real=False, show_imag=False,
671 show_window=False, rmax=None, label=None, title=None,
672 offset=0, show=True, fig=None):
673 """
674 plot_chir(dgroup, show_mag=True, show_real=False, show_imag=False,
675 rmax=None, label=None, fig=None)
677 Plot chi(R) for XAFS data group
679 Arguments
680 ----------
681 dgroup group of XAFS data after xftf() results (see Note 1)
682 show_mag bool whether to plot |chi(R)| [True]
683 show_real bool whether to plot Re[chi(R)] [False]
684 show_imag bool whether to plot Im[chi(R)] [False]
685 show_window bool whether to R-windw for back FT (will be scaled) [False]
686 label string for label [``None`` to use 'chir']
687 title string for plot title [None, may use filename if available]
688 rmax max R to show [None, end of data]
689 offset vertical offset to use for y-array [0]
690 show display the BokehFig now [True]
691 fig BokehFigure to re-use [None]
693 Notes
694 -----
695 1. The input data group must have the following attributes:
696 r, chir_mag, chir_im, chir_re, kweight, filename
697 """
698 kweight = _get_kweight(dgroup, None)
700 title = _get_title(dgroup, title=title)
702 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag,
703 show_real=show_real, show_imag=show_imag)
705 if not hasattr(dgroup, 'r'):
706 print("group does not have chi(R) data")
707 return
708 #endif
709 if label is None:
710 label = 'chir'
712 if fig is None:
713 fig = BokehFigure()
714 if show_mag:
715 fig.add_plot(dgroup.r, dgroup.chir_mag+offset, label=f'{label} (mag)')
716 if show_real:
717 fig.add_plot(dgroup.r, dgroup.chir_re+offset, label=f'{label} (real)')
719 if show_imag:
720 fig.add_plot(dgroup.r, dgroup.chir_im+offset, label=f'{label} (imag)')
722 if show_window and hasattr(dgroup, 'rwin'):
723 rwin = dgroup.rwin * max(dgroup.chir_mag)
724 fig.add_plot(dgroup.r, rwin+offset, label='window')
726 return fig.show(title=title, xlabel=plotlabels.r, ylabel=ylabel, xmax=rmax, show=show)
729def plot_chiq(dgroup, kweight=None, kmin=0, kmax=None, show_chik=False, label=None,
730 title=None, offset=0, show_window=False, scale_window=True,
731 show=True, fig=None):
732 """
733 plot_chiq(dgroup, kweight=None, kmax=None, show_chik=False, label=None,
734 new=True, win=1)
736 Plot Fourier filtered chi(k), optionally with k-weighted chi(k) for XAFS data group
738 Arguments
739 ----------
740 dgroup group of XAFS data after autobk() results (see Note 1)
741 kweight k-weighting for plot [read from last xftf(), or 0]
742 kmax max k to show [None, end of data]
743 show_chik bool whether to also plot k-weighted chi(k) [False]
744 show_window bool whether to also plot FT k-window [False]
745 scale_window bool whether to scale FT k-window to max |chi(q)| [True]
746 label string for label [``None`` to use 'chi']
747 title string for plot title [None, may use filename if available]
748 offset vertical offset to use for y-array [0]
749 show display the BokehFig now [True]
750 fig BokehFigure to re-use [None]
752 Notes
753 -----
754 1. The input data group must have the following attributes:
755 k, chi, kwin, filename
756 """
757 kweight = _get_kweight(dgroup, kweight)
758 nk = len(dgroup.k)
759 chiq = dgroup.chiq_re[:nk]
761 if label is None:
762 label = 'chi(q) (filtered)'
764 title = _get_title(dgroup, title=title)
765 if fig is None:
766 fig = BokehFigure()
767 fig.add_plot(dgroup.k, chiq+offset, label=label)
768 if kmax is None:
769 kmax = max(dgroup.k)
771 if show_chik:
772 chik = dgroup.chi * dgroup.k ** kweight
773 fig.add_plot(dgroup.k, chik+offset, label='chi(k) (unfiltered)')
775 if show_window and hasattr(dgroup, 'kwin'):
776 kwin = dgroup.kwin
777 if scale_window:
778 kwin = kwin*max(abs(chiq))
779 fig.add_plot(dgroup.k, kwin+offset, label='window')
781 ylabel = set_label_weight(plotlabels.chikw, kweight)
782 return fig.show(title=title, xlabel=plotlabels.k,
783 ylabel=ylabel, xmin=kmin, xmax=kmax, show=show)
787def plot_chifit(dataset, kmin=0, kmax=None, kweight=None, rmax=None,
788 show_mag=True, show_real=False, show_imag=False,
789 show_bkg=False, use_rebkg=False, title=None, offset=0):
790 """
791 plot_chifit(dataset, kmin=0, kmax=None, rmax=None,
792 show_mag=True, show_real=False, show_imag=False)
794 Plot k-weighted chi(k) and chi(R) for fit to feffit dataset
796 Arguments
797 ----------
798 dataset feffit dataset, after running feffit()
799 kmin min k to show [0]
800 kmax max k to show [None, end of data]
801 kweight kweight to show [None, taken from dataset]
802 rmax max R to show [None, end of data]
803 show_mag bool whether to plot |chidr(R)| [True]
804 show_real bool whether to plot Re[chi(R)] [False]
805 show_imag bool whether to plot Im[chi(R)] [False]
806 title string for plot title [None, may use filename if available]
807 offset vertical offset to use for y-array [0]
810 """
811 if kweight is None:
812 kweight = dataset.transform.kweight
813 #endif
814 if isinstance(kweight, (list, tuple, np.ndarray)):
815 kweight=kweight[0]
817 title = _get_title(dataset, title=title)
819 mod = dataset.model
820 dat = dataset.data
821 if use_rebkg and hasattr(dataset, 'data_rebkg'):
822 dat = dataset.data_rebkg
823 title += ' (refined bkg)'
825 data_chik = dat.chi * dat.k**kweight
826 model_chik = mod.chi * mod.k**kweight
828 # k-weighted chi(k) in first plot window
829 fig = BokehFigure()
830 fig.add_plot(dat.k, data_chik+offset, label='data')
831 fig.add_plot(mod.k, model_chik+offset, label='fit')
833 ylabel = set_label_weight(plotlabels.chikw, kweight)
834 fig.show(title=title, xlabel=plotlabels.k,
835 ylabel=ylabel, xmin=kmin, xmax=kmax)
837 # chi(R) in first plot window
838 rfig = BokehFigure()
840 if show_mag:
841 rfig.add_plot(dat.r, dat.chir_mag+offset, label='|data|')
842 rfig.add_plot(mod.r, mod.chir_mag+offset, label='|fit|')
844 if show_real:
845 rfig.add_plot(dat.r, dat.chir_re+offset, label='Re[data]')
846 rfig.add_plot(mod.r, mod.chir_re+offset, label='Re[fit]')
847 if show_imag:
848 rfig.add_plot(dat.r, dat.chir_im+offset, label='Im[data]')
849 rfig.add_plot(mod.r, mod.chir_im+offset, label='Im[fit]')
851 ylabel = chirlab(kweight, show_mag=show_mag, show_real=show_real, show_imag=show_imag)
852 rfig.show(title=title, xlabel=plotlabels.r, ylabel=ylabel, xmin=0, xmax=rmax)
853 return fig, rfig
855def plot_path_k(dataset, ipath=0, kmin=0, kmax=None, offset=0, label=None, fig=None):
856 """
857 plot_path_k(dataset, ipath, kmin=0, kmax=None, offset=0, label=None)
859 Plot k-weighted chi(k) for a single Path of a feffit dataset
861 Arguments
862 ----------
863 dataset feffit dataset, after running feffit()
864 ipath index of path, starting count at 0 [0]
865 kmin min k to show [0]
866 kmax max k to show [None, end of data]
867 offset vertical offset to use for plot [0]
868 label path label ['path %d' % ipath]
869 fig BokehFigure for reuse
870 """
871 kweight = dataset.transform.kweight
872 path = dataset.pathlist[ipath]
873 if label is None:
874 label = 'path %i' % (1+ipath)
875 title = _get_title(dataset, title=title)
877 chi_kw = offset + path.chi * path.k**kweight
878 if fig is None:
879 fig = BokehFigure()
880 fig.add_plot(path.k, chi_kw, label=label)
881 return fig.set_style(title=title, xlabel=plotlabels.k,
882 yabel=set_label_weight(plotlabels.chikw, kweight),
883 xmin=kmin, xmax=kmax)
885def plot_path_r(dataset, ipath, rmax=None, offset=0, label=None,
886 show_mag=True, show_real=False, show_imag=True, fig=None):
887 """
888 plot_path_r(dataset, ipath,rmax=None, offset=0, label=None,
889 show_mag=True, show_real=False, show_imag=True, fig=None)
891 Plot chi(R) for a single Path of a feffit dataset
893 Arguments
894 ----------
895 dataset feffit dataset, after running feffit()
896 ipath index of path, starting count at 0 [0]
897 rmax max R to show [None, end of data]
898 offset vertical offset to use for plot [0]
899 label path label ['path %d' % ipath]
900 show_mag bool whether to plot |chi(R)| [True]
901 show_real bool whether to plot Re[chi(R)] [False]
902 show_imag bool whether to plot Im[chi(R)] [False]
903 fig BokehFigure for reuse
904 """
905 path = dataset.pathlist[ipath]
906 if label is None:
907 label = 'path %i' % (1+ipath)
909 title = _get_title(dataset, title=title)
910 kweight =dataset.transform.kweight
911 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag,
912 show_real=show_real, show_imag=show_imag)
914 if fig is None:
915 fig = BokehFigure()
916 if show_mag:
917 fig.add_plot(path.r, offset+path.chir_mag, label=f'|{label}|')
919 if show_real:
920 fig.add_plot(path.r, offset+path.chir_re, label=f'Re[{label}|')
922 if show_imag:
923 fig.add_plot(path.r, offset+path.chir_im, label=f'Im[{label}|')
925 return fig.show(title=title, xlabel=plotlabels.r, ylabel=chirlab(kweight),
926 xmax=rmax)
929def plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, title=None, fig=None):
930 """
931 plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, fig=None)
933 Plot k-weighted chi(k) for model and all paths of a feffit dataset
935 Arguments
936 ----------
937 dataset feffit dataset, after running feffit()
938 kmin min k to show [0]
939 kmax max k to show [None, end of data]
940 offset vertical offset to use for paths for plot [-1]
941 title string for plot title [None, may use filename if available]
942 fig BokehFigure for reuse
943 """
944 # make k-weighted chi(k)
945 kweight = dataset.transform.kweight
946 model = dataset.model
948 model_chi_kw = model.chi * model.k**kweight
950 title = _get_title(dataset, title=title)
951 if fig is None:
952 fig = BokehFigure()
953 fig.add_plot(model.k, model_chi_kw, label='sum')
955 for ipath in range(len(dataset.pathlist)):
956 path = dataset.pathlist[ipath]
957 label = 'path %i' % (1+ipath)
958 chi_kw = offset*(1+ipath) + path.chi * path.k**kweight
959 fig.add_plot(path.k, chi_kw, label=label)
961 return fig.show(title=title, xlabel=plotlabels.k,
962 ylabel=set_label_weight(plotlabels.chikw, kweight),
963 xmin=kmin, xmax=kmax)
965def plot_paths_r(dataset, offset=-0.25, rmax=None, show_mag=True,
966 show_real=False, show_imag=False, title=None, fig=None):
967 """
968 plot_paths_r(dataset, offset=-0.5, rmax=None, show_mag=True, show_real=False,
969 show_imag=False)
971 Plot chi(R) for model and all paths of a feffit dataset
973 Arguments
974 ----------
975 dataset feffit dataset, after running feffit()
976 offset vertical offset to use for paths for plot [-0.5]
977 rmax max R to show [None, end of data]
978 show_mag bool whether to plot |chi(R)| [True]
979 show_real bool whether to plot Re[chi(R)] [False]
980 show_imag bool whether to plot Im[chi(R)] [False]
981 title string for plot title [None, may use filename if available]
982 fig BokehFigure for reuse
983 """
984 kweight = dataset.transform.kweight
985 model = dataset.model
987 title = _get_title(dataset, title=title)
988 if fig is None:
989 fig = BokehFigure()
991 if show_mag:
992 fig.add_plot(model.r, model.chir_mag, label='|sum|')
994 if show_real:
995 fig.add_plot(model.r, model.chir_re, label='Re[sum]')
997 if show_imag:
998 fig.add_plot(model.r, model.chir_re, label='Im[sum]')
1000 for ipath in range(len(dataset.pathlist)):
1001 path = dataset.pathlist[ipath]
1002 label = 'path %i' % (1+ipath)
1003 off = (ipath+1)*offset
1004 if show_mag:
1005 fig.add_plot(path.r, off+path.chir_mag, label=f'|{label}|')
1007 if show_real:
1008 fig.add_plot(path.r, off+path.chir_re, label=f'Re[{label}]')
1010 if show_imag:
1011 fig.add_plot(path.r, off+path.chir_im, label=f'Im[{label}]')
1013 return fig.show(title=title, xlabel=plotlabels.r,
1014 ylabel=chirlab(kweight), xmax=rmax)
1016def plot_prepeaks_baseline(dgroup, subtract_baseline=False, show_fitrange=True,
1017 show_peakrange=True):
1018 """Plot pre-edge peak baseline fit, as from `pre_edge_baseline` or XAS Viewer
1020 dgroup must have a 'prepeaks' attribute
1021 """
1022 if not hasattr(dgroup, 'prepeaks'):
1023 raise ValueError('Group needs prepeaks')
1024 #endif
1025 ppeak = dgroup.prepeaks
1027 px0, px1, py0, py1 = extend_plotrange(dgroup.xdat, dgroup.ydat,
1028 xmin=ppeak.emin, xmax=ppeak.emax)
1030 title = "pre_edge baseline\n %s" % dgroup.filename
1032 fig = BokehFigure()
1034 ydat = dgroup.ydat
1035 xdat = dgroup.xdat
1036 if subtract_baseline:
1037 fig.add_plot(ppeak.energy, ppeak.baseline, label='baseline subtracted peaks')
1038 else:
1039 fig.add_plot(ppeak.energy, ppeak.baseline, label='baseline')
1040 fig.add_plot(xdat, ydat, label='data')
1042 if show_fitrange:
1043 for x in (ppeak.emin, ppeak.emax):
1044 fig.add_vline(x=x, line_width=2, line_dash="dash", line_color="#DDDDCC")
1045 fig.add_vline(x=ppeak.centroid, line_width=2, line_dash="dash", line_color="#EECCCC")
1047 if show_peakrange:
1048 for x in (ppeak.elo, ppeak.ehi):
1049 y = ydat[index_of(xdat, x)]
1050 fig.add_plot([x], [y], marker='o', marker_size=7)
1052 return fig.show(title=title, xlabel=plotlabels.energy, ylabel='mu (normalized)',
1053 xmin=px0, xmax=px1, ymin=py0, ymax=py1)
1056def plot_prepeaks_fit(dgroup, nfit=0, show_init=False, subtract_baseline=False,
1057 show_residual=False):
1058 """plot pre-edge peak fit, as from Larix
1060 dgroup must have a 'peakfit_history' attribute
1061 """
1062 if not hasattr(dgroup, 'prepeaks'):
1063 raise ValueError('Group needs prepeaks')
1064 #endif
1065 if show_init:
1066 result = pkfit = dgroup.prepeaks
1067 else:
1068 hist = getattr(dgroup.prepeaks, 'fit_history', None)
1069 if nfit > len(hist):
1070 nfit = 0
1071 pkfit = hist[nfit]
1072 result = pkfit.result
1073 #endif
1075 if pkfit is None:
1076 raise ValueError('Group needs prepeaks.fit_history or init_fit')
1077 #endif
1079 opts = pkfit.user_options
1080 xeps = min(np.diff(dgroup.xdat)) / 5.
1081 xdat = 1.0*pkfit.energy
1082 ydat = 1.0*pkfit.norm
1084 xdat_full = 1.0*dgroup.xdat
1085 ydat_full = 1.0*dgroup.ydat
1087 if show_init:
1088 yfit = pkfit.init_fit
1089 ycomps = None # pkfit.init_ycomps
1090 ylabel = 'model'
1091 else:
1092 yfit = 1.0*result.best_fit
1093 ycomps = pkfit.ycomps
1094 ylabel = 'best fit'
1096 baseline = 0.*ydat
1097 if ycomps is not None:
1098 for label, ycomp in ycomps.items():
1099 if label in opts['bkg_components']:
1100 baseline += ycomp
1102 fig = BokehFigure()
1103 title ='%s:\npre-edge peak' % dgroup.filename
1107 if subtract_baseline:
1108 ydat -= baseline
1109 yfit -= baseline
1110 ydat_full = 1.0*ydat
1111 xdat_full = 1.0*xdat
1112 plotopts['ylabel'] = '%s-baseline' % plotopts['ylabel']
1114 dx0, dx1, dy0, dy1 = extend_plotrange(xdat_full, ydat_full,
1115 xmin=opts['emin'], xmax=opts['emax'])
1116 fx0, fx1, fy0, fy1 = extend_plotrange(xdat, yfit,
1117 xmin=opts['emin'], xmax=opts['emax'])
1119 ncolor = 0
1120 popts = {}
1121 plotopts.update(popts)
1122 dymin = dymax = None
1124 fig.add_plot(xdat, ydat, label='data')
1125 fig.add_plot(xday, yfit, label='fit')
1127 if show_residual:
1128 dfig = BokehFigure()
1129 dfig.add_plot(xdat, yfit-ydat, label='fit-data')
1130 dy = yfit - ydat
1131 dymax, dymin = dy.max(), dy.min()
1132 dymax += 0.05 * (dymax - dymin)
1133 dymin -= 0.05 * (dymax - dymin)
1135 if ycomps is not None:
1136 ncomps = len(ycomps)
1137 if not subtract_baseline:
1138 fig.add_plot(xdat, baseline, label='baseline')
1139 for icomp, label in enumerate(ycomps):
1140 ycomp = ycomps[label]
1141 if label in opts['bkg_components']:
1142 continue
1143 fig.add_plot(xdat, ycomp, label=label)
1145 if opts.get('show_fitrange', False):
1146 for attr in ('emin', 'emax'):
1147 fig.add_vline(opts[attr], line_width=2, line_dash="dash", line_color="#DDDDCC")
1149 if opts.get('show_centroid', False):
1150 pcen = getattr(dgroup.prepeaks, 'centroid', None)
1151 if hasattr(result, 'params'):
1152 pcen = result.params.get('fit_centroid', None)
1153 if pcen is not None:
1154 pcen = pcen.value
1155 if pcen is not None:
1156 fig.add_vlinee(pcen, color='#EECCCC')
1158 fig.show(title=title, xlabel=plotlabels.energy, ylabel=opts['array_desc'])
1159 dfig.show(title=tile, ylabel='fit-data', ymin=dymin, ymax=dymax)
1160 return fig, dfig
1163def _pca_ncomps(result, min_weight=0, ncomps=None):
1164 if ncomps is None:
1165 if min_weight > 1.e-12:
1166 ncomps = np.where(result.variances < min_weight)[0][0]
1167 else:
1168 ncomps = np.argmin(result.ind)
1169 return ncomps
1172def plot_pca_components(result, min_weight=0, ncomps=None, min_variance=1.e-5):
1173 """Plot components from PCA result
1175 result must be output of `pca_train`
1176 """
1177 title = "PCA components"
1179 ncomps = int(result.nsig)
1180 fig = BokehFigure()
1181 fig.add_plot(result.x, result.mean, label='Mean')
1182 for i, comp in enumerate(result.components):
1183 if result.variances[i] > min_variance:
1184 label = 'Comp# %d (%.4f)' % (i+1, result.variances[i])
1185 fig.add_plot(result.x, comp, label=label)
1187 return fig.show(title=title, xlabel=plotlabels.energy, ylabel=plotlabels.norm,
1188 xmin=result.xmin, xmax=result.xmax)
1190def plot_pca_weights(result, min_weight=0, ncomps=None):
1191 """Plot component weights from PCA result (aka SCREE plot)
1193 result must be output of `pca_train`
1194 """
1195 max_comps = len(result.components)-1
1197 title = "PCA Variances (SCREE) and Indicator Values"
1198 fig = BokehFigure()
1200 ncomps = max(1, int(result.nsig))
1202 x0, x1, y0, y1 = extend_plotrange(result.variances, result.variances)
1203 y0 = max(1.e-6, min(result.variances[:-1]))
1204 x = 1+np.arange(ncomps)
1205 y = result.variances[:ncomps]
1206 fig.add_plot(x, y, label='significant', style='solid', marker='o')
1208 xe = 1 + np.arange(ncomps-1, max_comps)
1209 ye = result.variances[ncomps-1:ncomps+max_comps]
1211 fig.add_plot(xe, ye, label='not significant', style='dashed', marker='o')
1212 fig.set_ylog()
1213 yi = result.ind[1:]
1214 xi = 1 + np.arange(len(yi))
1216 x0, x1, yimin, yimax = extend_plotrange(xi, yi)
1218 fig.add_plot(xi, result.ind[1:], y2label='Indicator Value',
1219 style='solid', side='right')
1220 # fig.update_yaxes(title_text='Indicator') # , secondary_y=True)
1221 return fig.show(title=title, xlabel='Component #', ylabel='variance')
1224def plot_pca_fit(dgroup, with_components=True):
1225 """Plot data and fit result from pca_fit, which rom PCA result
1227 result must be output of `pca_fit`
1228 """
1229 title = "PCA fit: %s" % (dgroup.filename)
1230 result = dgroup.pca_result
1231 model = result.pca_model
1233 fig = BokehFigure()
1234 fig.add_plot(result.x, result.ydat, label='data')
1235 fig.add_plot(result.x, result.yfit, label='fit')
1236 if with_components:
1237 fig.add_plot(result.x, model.mean, label='mean')
1238 for n in range(len(result.weights)):
1239 cval = model.components[n]*result.weights[n]
1240 fig.add_plot(result.x, cval, label='Comp #%d' % (n+1))
1242 fig.show(title=title, xmin=model.xmin, xmax=model.xmax,
1243 xlabel=plotlabels.energy, ylabel=plotlabels.norm)
1245 dfig = BokehFigure()
1246 dfig.add_plot(result.x, result.yfit-result.ydat, label='fit-data')
1247 dfig.show(title=title, xmin=model.xmin, xmax=model.xmax,
1248 xlabel=plotlabels.energy, ylabel='fit-data')
1249 return fig, dfig
1251def plot_diffkk(dgroup, emin=None, emax=None, new=True, label=None,
1252 title=None, offset=0):
1253 """
1254 plot_diffkk(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None):
1256 Plot mu(E) and background mu0(E) for XAFS data group
1258 Arguments
1259 ----------
1260 dgroup group of XAFS data after autobk() results (see Note 1)
1261 norm bool whether to show normalized data [True]
1262 emin min energy to show, absolute or relative to E0 [None, start of data]
1263 emax max energy to show, absolute or relative to E0 [None, end of data]
1264 show_e0 bool whether to show E0 [False]
1265 label string for label [``None``: 'mu']
1266 title string for plot title [None, may use filename if available]
1267 offset vertical offset to use for y-array [0]
1269 Notes
1270 -----
1271 1. The input data group must have the following attributes:
1272 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename
1273 """
1274 if hasattr(dgroup, 'f2'):
1275 f2 = dgroup.f2
1276 else:
1277 raise ValueError("Data group has no array for f2")
1278 #endif
1279 ylabel = r'$$f \rm\,\, (e^{-})$$ '
1280 emin, emax = _get_erange(dgroup, emin, emax)
1281 title = _get_title(dgroup, title=title)
1283 labels = {'f2': r"$$f_2(E)$$", 'fpp': r"$$f''(E)$$", 'fp': r"$$f'(E)$$", 'f1': r"$$f_1(E)$$"}
1285 fig = BokehFigure()
1286 fig.add_plot(dgroup.energy, f2, label=labels['f2'])
1288 for attr in ('fpp', 'f1', 'fp'):
1289 yval = getattr(dgroup, attr)
1290 if yval is not None:
1291 fig.add_plot(dgroup.energy, yval, label=labels[attr])
1293 return fig.show(title=title, xlabel=plotlabels.energy, yaxis_label=ylabel,
1294 xmin=emin, xmax=emax)
1297def plot_feffdat(feffpath, with_phase=True, title=None, fig=None):
1298 """
1299 plot_feffdat(feffpath, with_phase=True, title=None)
1301 Plot Feff's magnitude and phase as a function of k for a FeffPath
1303 Arguments
1304 ----------
1305 feffpath feff path as read by feffpath()
1306 with_pase whether to plot phase(k) as well as magnitude [True]
1307 title string for plot title [None, may use filename if available]
1309 Notes
1310 -----
1311 1. The input data group must have the following attributes:
1312 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename
1313 """
1314 if hasattr(feffpath, '_feffdat'):
1315 fdat = feffpath._feffdat
1316 else:
1317 raise ValueError("must pass in a Feff path as from feffpath()")
1319 if fig is None:
1320 fig = BokehFigure()
1321 fig.add_plot(result.x, result.ydat, label='data')
1324 fig.add_plot(fdat.k, fdat.mag_feff, label='magnitude')
1325 # xlabel=plotlabels.k,
1326 # ylabel='|F(k)|', title=title,
1328 if with_phase:
1329 fig.add_plot(fdat.k, fdat.pha_feff, label='phase')
1330 # fig.fig.update_yaxis(title_text='Phase(k)') #, secondary_y=True)
1331 return fig.show(title=title, xlabel=plotlabels.k, ylabel='|F(k)|')
1333#enddef
1335def plot_wavelet(dgroup, show_mag=True, show_real=False, show_imag=False,
1336 rmax=None, kmax=None, kweight=None, title=None):
1337 """
1338 plot_wavelet(dgroup, show_mag=True, show_real=False, show_imag=False,
1339 rmax=None, kmax=None, kweight=None, title=None)
1341 Plot wavelet for XAFS data group
1343 Arguments
1344 ----------
1345 dgroup group of XAFS data after xftf() results (see Note 1)
1346 show_mag bool whether to plot wavelet magnitude [True]
1347 show_real bool whether to plot real part of wavelet [False]
1348 show_imag bool whether to plot imaginary part of wavelet [False]
1349 title string for plot title [None, may use filename if available]
1350 rmax max R to show [None, end of data]
1351 kmax max k to show [None, end of data]
1352 kweight k-weight to use to construct wavelet [None, take from group]
1354 Notes
1355 -----
1356 The wavelet will be performed
1357 """
1358 print("Image display not yet available with larch+bokeh")
1359 kweight = _get_kweight(dgroup, kweight)
1360 cauchy_wavelet(dgroup, kweight=kweight, rmax_out=rmax)
1361 title = _get_title(dgroup, title=title)
1363 opts = dict(title=title, x=dgroup.k, y=dgroup.wcauchy_r, xmax=kmax,
1364 ymax=rmax, xlabel=plotlabels.k, ylabel=plotlabels.r,
1365 show_axis=True)
1366 if show_mag:
1367 _imshow(dgroup.wcauchy_mag, **opts)
1368 elif show_real:
1369 _imshow(dgroup.wcauchy_real, **opts)
1370 elif show_imag:
1371 _imshow(dgroup.wcauchy_imag, **opts)
1372 #endif
1373#enddef