diff --git a/notebooks/Spectroscopy/Analyse_Low_Loss.ipynb b/notebooks/Spectroscopy/Analyse_Low_Loss.ipynb index 499ebea8..c6bc68cb 100644 --- a/notebooks/Spectroscopy/Analyse_Low_Loss.ipynb +++ b/notebooks/Spectroscopy/Analyse_Low_Loss.ipynb @@ -114,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": { "ExecuteTime": { "start_time": "2024-01-15T14:40:42.347318700Z" @@ -129,8 +129,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n", + "You don't have igor2 installed. If you wish to open igor files, you will need to install it (pip install igor2) before attempting.\n", + "You don't have gwyfile installed. If you wish to open .gwy files, you will need to install it (pip install gwyfile) before attempting.\n", + "Symmetry functions of spglib enabled\n", + "Using kinematic_scattering library version {_version_ } by G.Duscher\n", "pyTEM version: 0.2024.05.0\n" ] } @@ -181,14 +183,7 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 4, + "execution_count": 33, "metadata": { "hideCode": false, "hidePrompt": false, @@ -198,7 +193,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "4b0c8ab2efb34478b8efded845dafbfc", + "model_id": "398ee7476e5b446bb9b6ac1dd4b57d0a", "version_major": 2, "version_minor": 0 }, @@ -220,24 +215,45 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 35, "metadata": {}, "outputs": [ { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b6fe6f4d3c3849c2af8efb7264ff2074", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "AppLayout(children=(GridspecLayout(children=(ToggleButton(value=False, button_style='info', description='Fit A…" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "ValueError", + "evalue": "operands could not be broadcast together with shapes (0,) (1973,) ", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[35], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m infoWidget\u001b[38;5;241m.\u001b[39mcore_loss\u001b[38;5;241m.\u001b[39mdo_fit(\u001b[38;5;241m1\u001b[39m)\n", + "File \u001b[1;32m~\\Documents\\Github\\pyTEMlib\\notebooks\\Spectroscopy\\../..\\pyTEMlib\\core_loss_widget.py:441\u001b[0m, in \u001b[0;36mCoreLoss.do_fit\u001b[1;34m(self, value)\u001b[0m\n\u001b[0;32m 439\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 440\u001b[0m spectrum \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\n\u001b[1;32m--> 441\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39medges \u001b[38;5;241m=\u001b[39m eels\u001b[38;5;241m.\u001b[39mfit_edges2(spectrum, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparent\u001b[38;5;241m.\u001b[39menergy_scale, edges)\n\u001b[0;32m 442\u001b[0m areal_density \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m 443\u001b[0m elements \u001b[38;5;241m=\u001b[39m []\n", + "File \u001b[1;32m~\\Documents\\Github\\pyTEMlib\\notebooks\\Spectroscopy\\../..\\pyTEMlib\\eels_tools.py:1432\u001b[0m, in \u001b[0;36mfit_edges2\u001b[1;34m(spectrum, energy_scale, edges)\u001b[0m\n\u001b[0;32m 1428\u001b[0m \u001b[38;5;66;03m########################\u001b[39;00m\n\u001b[0;32m 1429\u001b[0m \u001b[38;5;66;03m# Background Fit\u001b[39;00m\n\u001b[0;32m 1430\u001b[0m \u001b[38;5;66;03m########################\u001b[39;00m\n\u001b[0;32m 1431\u001b[0m bgd_fit_area \u001b[38;5;241m=\u001b[39m [background_fit_start, background_fit_end]\n\u001b[1;32m-> 1432\u001b[0m background, [A, r] \u001b[38;5;241m=\u001b[39m power_law_background(spectrum, energy_scale, bgd_fit_area, verbose\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[0;32m 1434\u001b[0m \u001b[38;5;66;03m#######################\u001b[39;00m\n\u001b[0;32m 1435\u001b[0m \u001b[38;5;66;03m# Edge Fit\u001b[39;00m\n\u001b[0;32m 1436\u001b[0m \u001b[38;5;66;03m#######################\u001b[39;00m\n\u001b[0;32m 1437\u001b[0m x \u001b[38;5;241m=\u001b[39m energy_scale\n", + "File \u001b[1;32m~\\Documents\\Github\\pyTEMlib\\notebooks\\Spectroscopy\\../..\\pyTEMlib\\eels_tools.py:1376\u001b[0m, in \u001b[0;36mpower_law_background\u001b[1;34m(spectrum, energy_scale, fit_area, verbose)\u001b[0m\n\u001b[0;32m 1373\u001b[0m err \u001b[38;5;241m=\u001b[39m yy \u001b[38;5;241m-\u001b[39m power_law(xx, pp[\u001b[38;5;241m0\u001b[39m], pp[\u001b[38;5;241m1\u001b[39m])\n\u001b[0;32m 1374\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m err\n\u001b[1;32m-> 1376\u001b[0m [p, _] \u001b[38;5;241m=\u001b[39m leastsq(bgdfit, p0, args\u001b[38;5;241m=\u001b[39m(y, x), maxfev\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2000\u001b[39m)\n\u001b[0;32m 1378\u001b[0m background_difference \u001b[38;5;241m=\u001b[39m y \u001b[38;5;241m-\u001b[39m power_law(x, p[\u001b[38;5;241m0\u001b[39m], p[\u001b[38;5;241m1\u001b[39m])\n\u001b[0;32m 1379\u001b[0m background_noise_level \u001b[38;5;241m=\u001b[39m std_dev \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mstd(background_difference)\n", + "File \u001b[1;32m~\\AppData\\Local\\anaconda3\\Lib\\site-packages\\scipy\\optimize\\_minpack_py.py:420\u001b[0m, in \u001b[0;36mleastsq\u001b[1;34m(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)\u001b[0m\n\u001b[0;32m 418\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(args, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[0;32m 419\u001b[0m args \u001b[38;5;241m=\u001b[39m (args,)\n\u001b[1;32m--> 420\u001b[0m shape, dtype \u001b[38;5;241m=\u001b[39m _check_func(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mleastsq\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfunc\u001b[39m\u001b[38;5;124m'\u001b[39m, func, x0, args, n)\n\u001b[0;32m 421\u001b[0m m \u001b[38;5;241m=\u001b[39m shape[\u001b[38;5;241m0\u001b[39m]\n\u001b[0;32m 423\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m>\u001b[39m m:\n", + "File \u001b[1;32m~\\AppData\\Local\\anaconda3\\Lib\\site-packages\\scipy\\optimize\\_minpack_py.py:29\u001b[0m, in \u001b[0;36m_check_func\u001b[1;34m(checker, argname, thefunc, x0, args, numinputs, output_shape)\u001b[0m\n\u001b[0;32m 27\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_check_func\u001b[39m(checker, argname, thefunc, x0, args, numinputs,\n\u001b[0;32m 28\u001b[0m output_shape\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m---> 29\u001b[0m res \u001b[38;5;241m=\u001b[39m atleast_1d(thefunc(\u001b[38;5;241m*\u001b[39m((x0[:numinputs],) \u001b[38;5;241m+\u001b[39m args)))\n\u001b[0;32m 30\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (output_shape \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;129;01mand\u001b[39;00m (shape(res) \u001b[38;5;241m!=\u001b[39m output_shape):\n\u001b[0;32m 31\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (output_shape[\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m):\n", + "File \u001b[1;32m~\\Documents\\Github\\pyTEMlib\\notebooks\\Spectroscopy\\../..\\pyTEMlib\\eels_tools.py:1373\u001b[0m, in \u001b[0;36mpower_law_background..bgdfit\u001b[1;34m(pp, yy, xx)\u001b[0m\n\u001b[0;32m 1372\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mbgdfit\u001b[39m(pp, yy, xx):\n\u001b[1;32m-> 1373\u001b[0m err \u001b[38;5;241m=\u001b[39m yy \u001b[38;5;241m-\u001b[39m power_law(xx, pp[\u001b[38;5;241m0\u001b[39m], pp[\u001b[38;5;241m1\u001b[39m])\n\u001b[0;32m 1374\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m err\n", + "\u001b[1;31mValueError\u001b[0m: operands could not be broadcast together with shapes (0,) (1973,) " + ] } ], + "source": [ + "infoWidget.core_loss.do_fit(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "del infoWidget.core_loss.edges" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "\n", "datasets = {'Channel_000': infoWidget.datasets['Channel_000']}\n", diff --git a/pyTEMlib/core_loss_widget.py b/pyTEMlib/core_loss_widget.py new file mode 100644 index 00000000..ff79452e --- /dev/null +++ b/pyTEMlib/core_loss_widget.py @@ -0,0 +1,595 @@ +""" +Author: Gerd Duscher +""" + + +import numpy as np +import warnings + +import ipywidgets +import IPython.display +# from IPython.display import display +import matplotlib +import matplotlib.pylab as plt +import matplotlib.patches as patches + +from pyTEMlib import file_tools as ft +from pyTEMlib import eels_tools as eels +from pyTEMlib import eels_dialog_utilities + +import sidpy + + +def get_core_loss_sidebar(): + side_bar = ipywidgets.GridspecLayout(15, 3,width='auto', grid_gap="0px") + + side_bar[0, :2] = ipywidgets.Dropdown( + options=[('None', 0)], + value=0, + description='Main Dataset:', + disabled=False) + + row = 1 + side_bar[row, :3] = ipywidgets.ToggleButton(description='Fit Area', + layout=ipywidgets.Layout(width='auto', grid_area='header'), + tooltip='Shows fit regions and regions excluded from fit', + button_style='info') #ipywidgets.ButtonStyle(button_color='lightblue')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Fit Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Fit End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px')) + + row += 1 + + side_bar[row, :3] = ipywidgets.Button(description='Elements', + layout=ipywidgets.Layout(width='auto', grid_area='header'), + style=ipywidgets.ButtonStyle(button_color='lightblue')) + row += 1 + side_bar[row, :2] = ipywidgets.Dropdown( + options=[('Edge 1', 0), ('Edge 2', 1), ('Edge 3', 2), ('Edge 4', 3),('Add Edge', -1)], + value=0, + description='Edges:', + disabled=False, + layout=ipywidgets.Layout(width='200px')) + """side_bar[row,2] = ipywidgets.ToggleButton( + description='Regions', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Shows fit regions and regions excluded from fit', + layout=ipywidgets.Layout(width='100px') + ) + """ + row += 1 + side_bar[row, :2] = ipywidgets.IntText(value=7.5,description='Z:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px')) + row += 1 + side_bar[row, :2] = ipywidgets.Dropdown( + options=['K1','L3', 'M5', 'M3', 'M1', 'N7', 'N5', 'N3', 'N1'], + value='K1', + description='Symmetry:', + disabled=False, + layout=ipywidgets.Layout(width='200px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Onset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Mutliplier:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="a.u.", layout=ipywidgets.Layout(width='100px')) + row += 1 + + side_bar[row, :3] = ipywidgets.Button(description='Quantification', + layout=ipywidgets.Layout(width='auto', grid_area='header'), + style=ipywidgets.ButtonStyle(button_color='lightblue')) + + row += 1 + side_bar[row,0] = ipywidgets.ToggleButton( + description='Probabiity', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Changes y-axis to probability of flux is given', + layout=ipywidgets.Layout(width='100px') + ) + side_bar[row,1] = ipywidgets.ToggleButton( + description='Conv.LL', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Changes y-axis to probability of flux is given', + layout=ipywidgets.Layout(width='100px') + ) + side_bar[row,2] = ipywidgets.ToggleButton( + description='Show Edges', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Changes y-axis to probability of flux is given', + layout=ipywidgets.Layout(width='100px') + ) + + row += 1 + side_bar[row,0] = ipywidgets.ToggleButton( + description='Do All', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Fits all spectra of spectrum image', + layout=ipywidgets.Layout(width='100px') + ) + + side_bar[row,1] = ipywidgets.IntProgress(value=0, min=0, max=10, description=' ', bar_style='', # 'success', 'info', 'warning', 'danger' or '' + style={'bar_color': 'maroon'}, orientation='horizontal') + return side_bar + + + +class CoreLoss(object): + def __init__(self, sidebar=None, parent=None): + self.parent = parent + self.dataset = parent.dataset + self.core_loss_tab = sidebar + + self.model = [] + self.edges = {} + + self.periodic_table = eels_dialog_utilities.PeriodicTableWidget(self.parent.energy_scale) + self.elements_cancel_button = ipywidgets.Button(description='Cancel') + self.elements_select_button = ipywidgets.Button(description='Select') + self.elements_auto_button = ipywidgets.Button(description='Auto ID') + + self.periodic_table_panel = ipywidgets.VBox([self.periodic_table.periodic_table, + ipywidgets.HBox([self.elements_cancel_button, self.elements_auto_button, self.elements_select_button])]) + self.set_cl_action() + self.update_cl_sidebar() + + def update_cl_sidebar(self): + spectrum_list = ['None'] + for index, key in enumerate(self.parent.datasets.keys()): + if isinstance(self.parent.datasets[key], sidpy.Dataset): + if 'SPECTR' in self.parent.datasets[key].data_type.name: + energy_offset = self.parent.datasets[key].get_spectral_dims(return_axis=True)[0][0] + if energy_offset < 0: + spectrum_list.append(f'{key}: {self.parent.datasets[key].title}') + + self.core_loss_tab[0, 0].options = spectrum_list + + def line_select_callback(self, x_min, x_max): + self.start_cursor.value = np.round(x_min,3) + self.end_cursor.value = np.round(x_max, 3) + + self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value) + self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value) + + + def plot(self, scale=True): + self.parent.plot(scale=scale) + if len(self.model) > 1: + self.parent.axis.plot(self.parent.energy_scale, self.model, label='model') + self.parent.axis.plot(self.parent.energy_scale, self.dataset-self.model, label='difference') + + if self.core_loss_tab[13, 2].value: + self.show_edges() + if self.core_loss_tab[1, 0].value: + self.plot_regions() + self.parent.figure.canvas.draw_idle() + + + def plot_regions(self): + axis = self.parent.figure.gca() + y_min, y_max = axis.get_ylim() + height = y_max - y_min + + rect = [] + if 'fit_area' in self.edges: + color = 'blue' + alpha = 0.2 + x_min = self.edges['fit_area']['fit_start'] + width = self.edges['fit_area']['fit_end'] - x_min + rect.append(patches.Rectangle((x_min, y_min), width, height, + edgecolor=color, alpha=alpha, facecolor=color)) + axis.add_patch(rect[0]) + axis.text(x_min, y_max, 'fit region', verticalalignment='top') + color = 'red' + alpha = 0.5 + + for key in self.edges: + if key.isdigit(): + x_min = self.edges[key]['start_exclude'] + width = self.edges[key]['end_exclude']-x_min + rect.append(patches.Rectangle((x_min, y_min), width, height, + edgecolor=color, alpha=alpha, facecolor=color)) + axis.add_patch(rect[-1]) + axis.text(x_min, y_max, f"exclude\n edge {int(key)+1}", verticalalignment='top') + + def show_edges(self): + axis = self.parent.figure.gca() + x_min, x_max = axis.get_xlim() + y_min, y_max = axis.get_ylim() + + for key, edge in self.edges.items(): + i = 0 + if key.isdigit(): + element = edge['element'] + for sym in edge['all_edges']: + x = edge['all_edges'][sym]['onset'] + edge['chemical_shift'] + if x_min < x < x_max: + axis.text(x, y_max, '\n' * i + f"{element}-{sym}", + verticalalignment='top', color='black') + axis.axvline(x, ymin=0, ymax=1, color='gray') + i += 1 + + + def update_element(self, z=0, index=-1): + # We check whether this element is already in the + if z == 0: + z = self.core_loss_tab[6, 0].value + + zz = eels.get_z(z) + for key, edge in self.edges.items(): + if key.isdigit(): + if 'z' in edge: + if zz == edge['z']: + return False + + major_edge = '' + minor_edge = '' + all_edges = {} + x_section = eels.get_x_sections(zz) + edge_start = 10 # int(15./ft.get_slope(self.energy_scale)+0.5) + for key in x_section: + if len(key) == 2 and key[0] in ['K', 'L', 'M', 'N', 'O'] and key[1].isdigit(): + if self.parent.energy_scale[edge_start] < x_section[key]['onset'] < self.parent.energy_scale[-edge_start]: + if key in ['K1', 'L3', 'M5']: + major_edge = key + elif key in self.core_loss_tab[7, 0].options: + if minor_edge == '': + minor_edge = key + if int(key[-1]) % 2 > 0: + if int(minor_edge[-1]) % 2 == 0 or key[-1] > minor_edge[-1]: + minor_edge = key + + all_edges[key] = {'onset': x_section[key]['onset']} + + if major_edge != '': + key = major_edge + elif minor_edge != '': + key = minor_edge + else: + print(f'Could not find no edge of {zz} in spectrum') + return False + if index == -1: + index = self.core_loss_tab[5, 0].value + # self.ui.dialog.setWindowTitle(f'{index}, {zz}') + + if str(index) not in self.edges: + self.edges[str(index)] = {} + + start_exclude = x_section[key]['onset'] - x_section[key]['excl before'] + end_exclude = x_section[key]['onset'] + x_section[key]['excl after'] + + self.edges[str(index)] = {'z': zz, 'symmetry': key, 'element': eels.elements[zz], + 'onset': x_section[key]['onset'], 'end_exclude': end_exclude, + 'start_exclude': start_exclude} + self.edges[str(index)]['all_edges'] = all_edges + self.edges[str(index)]['chemical_shift'] = 0.0 + self.edges[str(index)]['areal_density'] = 0.0 + self.edges[str(index)]['original_onset'] = self.edges[str(index)]['onset'] + return True + + def sort_elements(self): + onsets = [] + for index, edge in self.edges.items(): + if index.isdigit(): + onsets.append(float(edge['onset'])) + + arg_sorted = np.argsort(onsets) + edges = self.edges.copy() + for index, i_sorted in enumerate(arg_sorted): + self.edges[str(index)] = edges[str(i_sorted)].copy() + + index = 0 + edge = self.edges['0'] + dispersion = self.parent.energy_scale[1]-self.parent.energy_scale[0] + + while str(index + 1) in self.edges: + next_edge = self.edges[str(index + 1)] + if edge['end_exclude'] > next_edge['start_exclude'] - 5 * dispersion: + edge['end_exclude'] = next_edge['start_exclude'] - 5 * dispersion + edge = next_edge + index += 1 + + if edge['end_exclude'] > self.parent.energy_scale[-3]: + edge['end_exclude'] = self.parent.energy_scale[-3] + + def set_elements(self, value=0): + selected_elements = self.periodic_table.get_output() + edges = self.edges.copy() + to_delete = [] + old_elements = [] + if len(selected_elements) > 0: + for key in self.edges: + if key.isdigit(): + if 'element' in self.edges[key]: + to_delete.append(key) + old_elements.append(self.edges[key]['element']) + + for key in to_delete: + edges[key] = self.edges[key] + del self.edges[key] + + for index, elem in enumerate(selected_elements): + if elem in old_elements: + self.edges[str(index)] = edges[str(old_elements.index(elem))] + else: + self.update_element(elem, index=index) + self.sort_elements() + self.update() + self.set_figure_pane() + + def set_element(self, elem): + self.update_element(self.core_loss_tab[6, 0].value) + # self.sort_elements() + self.update() + + + def set_fit_area(self, value): + if self.core_loss_tab[2, 0].value > self.core_loss_tab[3, 0].value: + self.core_loss_tab[2, 0].value = self.core_loss_tab[3, 0].value -1 + if self.core_loss_tab[2, 0].value < self.parent.energy_scale[0]: + self.core_loss_tab[2, 0].value = self.parent.energy_scale[0] + if self.core_loss_tab[3, 0].value > self.parent.energy_scale[-1]: + self.core_loss_tab[3, 0].value = self.parent.energy_scale[-1] + if 'fit_area' not in self.edges: + self.edges['fit_area'] = {} + self.edges['fit_area']['fit_start'] = self.core_loss_tab[2, 0].value + self.edges['fit_area']['fit_end'] = self.core_loss_tab[3, 0].value + + self.parent.plot() + + + def auto_id(self, value=0): + found_edges = eels.auto_id_edges(self.dataset) + if len(found_edges) > 0: + self.periodic_table.elements_selected = found_edges + self.periodic_table.update() + + def find_elements(self, value=0): + + if '0' not in self.edges: + self.edges['0'] = {} + # found_edges = eels.auto_id_edges(self.dataset) + found_edges = {} + + selected_elements = [] + elements = self.edges.copy() + + for key in self.edges: + if key.isdigit(): + if 'element' in self.edges[key]: + selected_elements.append(self.edges[key]['element']) + self.periodic_table.elements_selected = selected_elements + self.periodic_table.update() + self.parent.app_layout.center = self.periodic_table_panel # self.periodic_table.periodic_table + + def set_figure_pane(self, value=0): + self.parent.app_layout.center = self.parent.panel + + def update(self, index=0): + + index = self.core_loss_tab[5,0].value # which edge + if index < 0: + options = list(self.core_loss_tab[5, 0].options) + options.insert(-1, (f'Edge {len(self.core_loss_tab[5, 0].options)}', len(self.sidebar[4,0].options)-1)) + self.core_loss_tab[5, 0].options= options + self.core_loss_tab[5, 0].value = len(self.core_loss_tab[5, 0].options)-2 + if str(index) not in self.edges: + self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0, + 'areal_density': 0, 'chemical_shift':0} + if 'z' not in self.edges[str(index)]: + self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0, + 'areal_density': 0, 'chemical_shift':0} + edge = self.edges[str(index)] + + self.core_loss_tab[6,0].value = edge['z'] + self.core_loss_tab[6,2].value = edge['element'] + self.core_loss_tab[7,0].value = edge['symmetry'] + self.core_loss_tab[8,0].value = edge['onset'] + self.core_loss_tab[9,0].value = edge['start_exclude'] + self.core_loss_tab[10,0].value = edge['end_exclude'] + self.core_loss_tab[13, 0].value = self.parent.info_tab[9, 2].value + if self.parent.y_scale == 1.0: + self.core_loss_tab[11, 0].value = edge['areal_density'] + self.core_loss_tab[11, 2].value = 'a.u.' + else: + dispersion = self.parent.energy_scale[1]-self.parent.energy_scale[0] + self.core_loss_tab[11, 0].value = np.round(edge['areal_density']/self.dataset.metadata['experiment']['flux_ppm']*1e-6, 2) + self.core_loss_tab[11, 2].value = 'atoms/nm²' + + def do_fit(self, value=0): + if 'experiment' in self.dataset.metadata: + exp = self.dataset.metadata['experiment'] + if 'convergence_angle' not in exp: + raise ValueError('need a convergence_angle in experiment of metadata dictionary ') + alpha = exp['convergence_angle'] + beta = exp['collection_angle'] + beam_kv = exp['acceleration_voltage'] + + else: + raise ValueError('need a experiment parameter in metadata dictionary') + + eff_beta = eels.effective_collection_angle(self.parent.energy_scale, alpha, beta, beam_kv) + + self.low_loss = None + if self.core_loss_tab[13, 1].value: + for key in self.datasets.keys(): + if key != self.key: + if isinstance(self.datasets[key], sidpy.Dataset): + if self.datasets[key].data_type.name == 'SPECTRUM': + if self.datasets[key].energy_loss[0] < 0: + self.low_loss = self.datasets[key]/self.datasets[key].sum() + + edges = eels.make_cross_sections(self.edges, np.array(self.parent.energy_scale), beam_kv, eff_beta, self.low_loss) + + if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE: + spectrum = self.parent.get_spectrum() + else: + spectrum = self.dataset + self.edges = eels.fit_edges2(spectrum, self.parent.energy_scale, edges) + areal_density = [] + elements = [] + for key in edges: + if key.isdigit(): # only edges have numbers in that dictionary + elements.append(edges[key]['element']) + areal_density.append(edges[key]['areal_density']) + areal_density = np.array(areal_density) + out_string = '\nRelative composition: \n' + for i, element in enumerate(elements): + out_string += f'{element}: {areal_density[i] / areal_density.sum() * 100:.1f}% ' + + self.model = self.edges['model']['spectrum'] + self.update() + self.plot() + + def do_all_button_click(self, value=0): + if self.sidebar[13,0].value==False: + return + + if self.dataset.data_type.name != 'SPECTRAL_IMAGE': + self.do_fit() + return + + if 'experiment' in self.dataset.metadata: + exp = self.dataset.metadata['experiment'] + if 'convergence_angle' not in exp: + raise ValueError('need a convergence_angle in experiment of metadata dictionary ') + alpha = exp['convergence_angle'] + beta = exp['collection_angle'] + beam_kv = exp['acceleration_voltage'] + else: + raise ValueError('need a experiment parameter in metadata dictionary') + + eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv) + eff_beta = beta + self.low_loss = None + if self.sidebar[12, 1].value: + for key in self.datasets.keys(): + if key != self.key: + if isinstance(self.datasets[key], sidpy.Dataset): + if 'SPECTR' in self.datasets[key].data_type.name: + if self.datasets[key].energy_loss[0] < 0: + self.low_loss = self.datasets[key]/self.datasets[key].sum() + + edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss) + + view = self.parent + bin_x = view.bin_x + bin_y = view.bin_y + + start_x = view.x + start_y = view.y + + number_of_edges = 0 + for key in self.edges: + if key.isdigit(): + number_of_edges += 1 + + results = np.zeros([int(self.dataset.shape[0]/bin_x), int(self.dataset.shape[1]/bin_y), number_of_edges]) + total_spec = int(self.dataset.shape[0]/bin_x)*int(self.dataset.shape[1]/bin_y) + self.sidebar[13,1].max = total_spec + #self.ui.progress.setMaximum(total_spec) + #self.ui.progress.setValue(0) + ind = 0 + for x in range(int(self.dataset.shape[0]/bin_x)): + for y in range(int(self.dataset.shape[1]/bin_y)): + ind += 1 + self.sidebar[13,1].value = ind + view.x = x*bin_x + view.y = y*bin_y + spectrum = view.get_spectrum() + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + edges = eels.fit_edges2(spectrum, self.energy_scale, edges) + for key, edge in edges.items(): + if key.isdigit(): + # element.append(edge['element']) + results[x, y, int(key)] = edge['areal_density'] + edges['spectrum_image_quantification'] = results + self.sidebar[13,1].value = total_spec + view.x = start_x + view.y = start_y + self.sidebar[13,0].value = False + + + def modify_onset(self, value=-1): + edge_index = self.core_loss_tab[5, 0].value + edge = self.edges[str(edge_index)] + edge['onset'] = self.core_loss_tab[8,0].value + if 'original_onset' not in edge: + edge['original_onset'] = edge['onset'] + edge['chemical_shift'] = edge['onset'] - edge['original_onset'] + self.update() + + + def modify_start_exclude(self, value=-1): + edge_index = self.core_loss_tab[5, 0].value + edge = self.edges[str(edge_index)] + edge['start_exclude'] = self.core_loss_tab[9,0].value + self.plot() + + def modify_end_exclude(self, value=-1): + edge_index = self.core_loss_tab[5, 0].value + edge = self.edges[str(edge_index)] + edge['end_exclude'] = self.core_loss_tab[10,0].value + self.plot() + + def modify_areal_density(self, value=-1): + edge_index = self.core_loss_tab[5, 0].value + edge = self.edges[str(edge_index)] + + edge['areal_density'] = self.core_loss_tab[11, 0].value + if self.parent.y_scale != 1.0: + dispersion = self.parent.energy_scale[1]-self.parent.energy_scale[0] + edge['areal_density'] = self.core_loss_tab[11, 0].value *self.dataset.metadata['experiment']['flux_ppm']/1e-6 + if 'model' in self.edges: + self.model = self.edges['model']['background'] + for key in self.edges: + if key.isdigit(): + if 'data' in self.edges[key]: + self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data'] + self.model = self.edges['model']['background'] + for key in self.edges: + if key.isdigit(): + if 'data' in self.edges[key]: + self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data'] + self.plot() + + def set_y_scale(self, value): + self.parent.info_tab[9, 2].value = self.core_loss_tab[13,0].value + self.update() + + def set_cl_action(self): + self.core_loss_tab[2, 0].observe(self.set_fit_area, names='value') + self.core_loss_tab[3, 0].observe(self.set_fit_area, names='value') + + self.core_loss_tab[4, 0].on_click(self.find_elements) + self.core_loss_tab[5, 0].observe(self.update, names='value') + self.core_loss_tab[6, 0].observe(self.set_element, names='value') + + self.core_loss_tab[8, 0].observe(self.modify_onset, names='value') + self.core_loss_tab[9, 0].observe(self.modify_start_exclude, names='value') + self.core_loss_tab[10, 0].observe(self.modify_end_exclude, names='value') + self.core_loss_tab[11, 0].observe(self.modify_areal_density, names='value') + + self.core_loss_tab[12, 0].on_click(self.do_fit) + self.core_loss_tab[13, 2].observe(self.plot, names='value') + self.core_loss_tab[1, 0].observe(self.plot, names='value') + self.core_loss_tab[13,0].observe(self.set_y_scale, names='value') + self.core_loss_tab[14,0].observe(self.do_all_button_click, names='value') + + self.elements_cancel_button.on_click(self.set_figure_pane) + self.elements_auto_button.on_click(self.auto_id) + self.elements_select_button.on_click(self.set_elements) diff --git a/pyTEMlib/eels_dialog.py b/pyTEMlib/eels_dialog.py index 16c8dfa3..1897a697 100644 --- a/pyTEMlib/eels_dialog.py +++ b/pyTEMlib/eels_dialog.py @@ -93,7 +93,7 @@ def onpick(self, event): legline.set_alpha(0.2) self.fig.canvas.draw() -def get_sidebar(): +def get_core_loss_sidebar(): side_bar = ipywidgets.GridspecLayout(14, 3,width='auto', grid_gap="0px") @@ -194,6 +194,7 @@ def get_sidebar(): return side_bar + class CompositionWidget(object): def __init__(self, datasets=None, key=None): @@ -203,7 +204,7 @@ def __init__(self, datasets=None, key=None): self.model = [] - self.sidebar = get_sidebar() + self.sidebar = get_core_loss_sidebar() self.set_dataset(key) diff --git a/pyTEMlib/info_widget.py b/pyTEMlib/info_widget.py index 3323e545..2c3a8f85 100644 --- a/pyTEMlib/info_widget.py +++ b/pyTEMlib/info_widget.py @@ -11,6 +11,8 @@ # from pyTEMlib.microscope import microscope from pyTEMlib import file_tools from pyTEMlib import eels_tools +from pyTEMlib.core_loss_widget import get_core_loss_sidebar, CoreLoss +from pyTEMlib.low_loss_widget import get_low_loss_sidebar, LowLoss def get_image_sidebar() -> Any: side_bar = ipywidgets.GridspecLayout(14, 3, width='auto', grid_gap="0px") @@ -192,69 +194,6 @@ def get_info_sidebar() -> Any: side_bar[i, 0].layout.display = "none" return side_bar -def get_low_loss_sidebar() -> Any: - side_bar = ipywidgets.GridspecLayout(9, 3, width='auto', grid_gap="0px") - - side_bar[0, :2] = ipywidgets.Dropdown( - options=[('None', 0)], - value=0, - description='Main Dataset:', - disabled=False) - - row = 1 - - side_bar[row, :3] = ipywidgets.Button(description='Resolution Function', - layout=ipywidgets.Layout(width='auto', grid_area='header'), - style=ipywidgets.ButtonStyle(button_color='lightblue')) - row += 1 - side_bar[row, :2] = ipywidgets.FloatText(value=7.5, description='fit width:', disabled=False, color='black', - layout=ipywidgets.Layout(width='200px')) - side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) - row +=1 - side_bar[row, 0] = ipywidgets.widgets.Label(value="thickness", layout=ipywidgets.Layout(width='100px')) - side_bar[row, 1] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px')) - side_bar[row, 2] = ipywidgets.widgets.Label(value="* iMFP", layout=ipywidgets.Layout(width='100px')) - row +=1 - side_bar[row, 0] = ipywidgets.ToggleButton(description='Plot Res.Fct.', - disabled=False, - button_style='', # 'success', 'info', 'warning', 'danger' or '' - tooltip='Plots resolution function on right', - layout=ipywidgets.Layout(width='100px')) - - side_bar[row, 2] = ipywidgets.ToggleButton(description='Probability', - disabled=False, - button_style='', # 'success', 'info', 'warning', 'danger' or '' - tooltip='Changes y-axis to probability if flux is given', - layout=ipywidgets.Layout(width='100px')) - - - row += 1 - side_bar[row, :3] = ipywidgets.Button(description='Drude', - layout=ipywidgets.Layout(width='auto', grid_area='header'), - style=ipywidgets.ButtonStyle(button_color='lightblue')) - row += 1 - side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Start Fit:', disabled=False, color='black', - layout=ipywidgets.Layout(width='200px')) - side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) - row += 1 - side_bar[row, :2] = ipywidgets.FloatText(value=7.5, description='End Fit:', disabled=False, color='black', - layout=ipywidgets.Layout(width='200px')) - side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='50px')) - row +=1 - side_bar[row, 0] = ipywidgets.ToggleButton(description='Plot Drude', - disabled=False, - button_style='', # 'success', 'info', 'warning', 'danger' or '' - tooltip='Plots resolution function on right', - layout=ipywidgets.Layout(width='100px')) - - side_bar[row, 2] = ipywidgets.ToggleButton(description='Plot Diel.Fct.', - disabled=False, - button_style='', # 'success', 'info', 'warning', 'danger' or '' - tooltip='Changes y-axis to probability if flux is given', - layout=ipywidgets.Layout(width='100px')) - - - return side_bar def get_file_widget_ui(): @@ -753,14 +692,16 @@ class EELSWidget(EELSBaseWidget): def __init__(self, datasets=None): sidebar = {'Spec.': get_info_sidebar(), - 'Image': get_image_sidebar(), - 'LowLoss': get_low_loss_sidebar()} + 'LowLoss': get_low_loss_sidebar(), + 'CoreLoss': get_core_loss_sidebar()} super().__init__(datasets, sidebar) self.info_tab = sidebar['Spec.'] + self.core_loss_tab = sidebar['CoreLoss'] self.low_loss_tab = sidebar['LowLoss'] super().set_dataset() self.info = Info(self.info_tab, self) self.low_loss = LowLoss(self.low_loss_tab, self) + self.core_loss = CoreLoss(self.core_loss_tab, self) self.set_action() @@ -772,8 +713,10 @@ def tab_activated(self, val=0): self.update_sidebars() if val.new == 1: self.info.update_dataset() - elif val.new == 3: + elif val.new == 2: self.low_loss.update_ll_dataset() + elif val.new == 3: + self.low_loss.update_cl_dataset() def update_sidebars(self): if hasattr(self, 'info'): @@ -984,102 +927,3 @@ def set_action(self): self.info_tab[16, 0].observe(self.set_binning) self.info_tab[17, 0].observe(self.set_binning) - - -class LowLoss(object): - def __init__(self, sidebar=None, parent=None): - self.parent = parent - self.dataset = parent.dataset - self.low_loss_tab = sidebar - self.set_ll_action() - self.update_ll_sidebar() - - def update_ll_sidebar(self): - spectrum_list = ['None'] - for index, key in enumerate(self.parent.datasets.keys()): - if isinstance(self.parent.datasets[key], sidpy.Dataset): - if 'SPECTR' in self.parent.datasets[key].data_type.name: - energy_offset = self.parent.datasets[key].get_spectral_dims(return_axis=True)[0][0] - if energy_offset < 0: - spectrum_list.append(f'{key}: {self.parent.datasets[key].title}') - - self.low_loss_tab[0, 0].options = spectrum_list - - def get_resolution_function(self, value): - self.low_loss_tab[4, 0].value = False - zero_loss_fit_width=self.low_loss_tab[2, 0].value - self.parent.datasets['resolution_functions'] = eels_tools.get_resolution_functions(self.parent.dataset, - startFitEnergy=-zero_loss_fit_width, - endFitEnergy=zero_loss_fit_width) - if 'low_loss' not in self.dataset.metadata: - self.dataset.metadata['zero_loss'] = {} - self.dataset.metadata['zero_loss'].update(self.parent.datasets['resolution_functions'].metadata['zero_loss']) - self.low_loss_tab[4, 0].value = True - self.low_loss_tab[3, 1].value = f"{np.log(self.parent.dataset.sum()/self.parent.datasets['resolution_functions'].sum())}" - - - - def set_ll_action(self): - self.low_loss_tab[0, 0].observe(self.update_ll_dataset) - #self.low_loss_tab[1, 0].on_click(self.fix_energy_scale) - #self.low_loss_tab[2, 0].observe(self.set_energy_scale, names='value') - #self.low_loss_tab[3, 0].observe(self.set_energy_scale, names='value') - self.low_loss_tab[1, 0].on_click(self.get_resolution_function) - self.low_loss_tab[4, 2].observe(self.parent.info.set_y_scale, names='value') - self.low_loss_tab[4, 0].observe(self._update, names='value') - - def _update(self, ev=0): - self.parent._update(ev) - - if self.low_loss_tab[4, 0].value: - if 'resolution_functions' in self.parent.datasets: - resolution_function = self.get_additional_spectrum('resolution_functions') - self.parent.axis.plot(self.parent.energy_scale, resolution_function, label='resolution_function') - self.parent.axis.plot(self.parent.energy_scale, - self.parent.spectrum -resolution_function, label='difference') - - self.parent.axis.legend() - - def get_additional_spectrum(self, key): - if key not in self.parent.datasets.keys(): - return - - if self.parent.datasets[key].data_type == sidpy.DataType.SPECTRUM: - self.spectrum = self.parent.datasets[key].copy() - else: - image_dims = self.parent.datasets[key].get_dimensions_by_type(sidpy.DimensionType.SPATIAL) - selection = [] - for dim, axis in self.parent.datasets[key]._axes.items(): - # print(dim, axis.dimension_type) - if axis.dimension_type == sidpy.DimensionType.SPATIAL: - if dim == image_dims[0]: - selection.append(slice(self.x, self.x + self.bin_x)) - else: - selection.append(slice(self.y, self.y + self.bin_y)) - - elif axis.dimension_type == sidpy.DimensionType.SPECTRAL: - selection.append(slice(None)) - elif axis.dimension_type == sidpy.DimensionType.CHANNEL: - selection.append(slice(None)) - else: - selection.append(slice(0, 1)) - - self.spectrum = self.parent.datasets[key][tuple(selection)].mean(axis=tuple(image_dims)) - - self.spectrum *= self.parent.y_scale - - return self.spectrum.squeeze() - - def update_ll_dataset(self, value=0): - self.ll_key = self.low_loss_tab[0, 0].value.split(':')[0] - self.parent.set_dataset(self.ll_key) - self.dataset = self.parent.dataset - - - def set_binning(self, value): - if 'SPECTRAL' in self.dataset.data_type.name: - bin_x = self.info_tab[15, 0].value - bin_y = self.info_tab[16, 0].value - self.dataset.view.set_bin([bin_x, bin_y]) - self.datasets[self.key].metadata['experiment']['SI_bin_x'] = bin_x - self.datasets[self.key].metadata['experiment']['SI_bin_y'] = bin_y diff --git a/pyTEMlib/low_loss_widget.py b/pyTEMlib/low_loss_widget.py new file mode 100644 index 00000000..a78846a6 --- /dev/null +++ b/pyTEMlib/low_loss_widget.py @@ -0,0 +1,176 @@ +from typing import Any + +import numpy as np +import os +import ipywidgets +import matplotlib.pylab as plt +import matplotlib +from IPython.display import display + +import sidpy +# from pyTEMlib.microscope import microscope +from pyTEMlib import file_tools +from pyTEMlib import eels_tools + + +def get_low_loss_sidebar() -> Any: + side_bar = ipywidgets.GridspecLayout(9, 3, width='auto', grid_gap="0px") + + side_bar[0, :2] = ipywidgets.Dropdown( + options=[('None', 0)], + value=0, + description='Main Dataset:', + disabled=False) + + row = 1 + + side_bar[row, :3] = ipywidgets.Button(description='Resolution Function', + layout=ipywidgets.Layout(width='auto', grid_area='header'), + style=ipywidgets.ButtonStyle(button_color='lightblue')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=7.5, description='fit width:', disabled=False, color='black', + layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) + row +=1 + side_bar[row, 0] = ipywidgets.widgets.Label(value="thickness", layout=ipywidgets.Layout(width='100px')) + side_bar[row, 1] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="* iMFP", layout=ipywidgets.Layout(width='100px')) + row +=1 + side_bar[row, 0] = ipywidgets.ToggleButton(description='Plot Res.Fct.', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Plots resolution function on right', + layout=ipywidgets.Layout(width='100px')) + + side_bar[row, 2] = ipywidgets.ToggleButton(description='Probability', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Changes y-axis to probability if flux is given', + layout=ipywidgets.Layout(width='100px')) + + + row += 1 + side_bar[row, :3] = ipywidgets.Button(description='Drude', + layout=ipywidgets.Layout(width='auto', grid_area='header'), + style=ipywidgets.ButtonStyle(button_color='lightblue')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Start Fit:', disabled=False, color='black', + layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px')) + row += 1 + side_bar[row, :2] = ipywidgets.FloatText(value=7.5, description='End Fit:', disabled=False, color='black', + layout=ipywidgets.Layout(width='200px')) + side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='50px')) + row +=1 + side_bar[row, 0] = ipywidgets.ToggleButton(description='Plot Drude', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Plots resolution function on right', + layout=ipywidgets.Layout(width='100px')) + + side_bar[row, 2] = ipywidgets.ToggleButton(description='Plot Diel.Fct.', + disabled=False, + button_style='', # 'success', 'info', 'warning', 'danger' or '' + tooltip='Changes y-axis to probability if flux is given', + layout=ipywidgets.Layout(width='100px')) + + + return side_bar + +class LowLoss(object): + def __init__(self, sidebar=None, parent=None): + self.parent = parent + self.dataset = parent.dataset + self.low_loss_tab = sidebar + self.set_ll_action() + self.update_ll_sidebar() + + def update_ll_sidebar(self): + spectrum_list = ['None'] + for index, key in enumerate(self.parent.datasets.keys()): + if isinstance(self.parent.datasets[key], sidpy.Dataset): + if 'SPECTR' in self.parent.datasets[key].data_type.name: + energy_offset = self.parent.datasets[key].get_spectral_dims(return_axis=True)[0][0] + if energy_offset < 0: + spectrum_list.append(f'{key}: {self.parent.datasets[key].title}') + + self.low_loss_tab[0, 0].options = spectrum_list + + def get_resolution_function(self, value): + self.low_loss_tab[4, 0].value = False + zero_loss_fit_width=self.low_loss_tab[2, 0].value + self.parent.datasets['resolution_functions'] = eels_tools.get_resolution_functions(self.parent.dataset, + startFitEnergy=-zero_loss_fit_width, + endFitEnergy=zero_loss_fit_width) + if 'low_loss' not in self.dataset.metadata: + self.dataset.metadata['zero_loss'] = {} + self.dataset.metadata['zero_loss'].update(self.parent.datasets['resolution_functions'].metadata['zero_loss']) + self.low_loss_tab[4, 0].value = True + self.low_loss_tab[3, 1].value = f"{np.log(self.parent.dataset.sum()/self.parent.datasets['resolution_functions'].sum())}" + + + + def set_ll_action(self): + self.low_loss_tab[0, 0].observe(self.update_ll_dataset) + #self.low_loss_tab[1, 0].on_click(self.fix_energy_scale) + #self.low_loss_tab[2, 0].observe(self.set_energy_scale, names='value') + #self.low_loss_tab[3, 0].observe(self.set_energy_scale, names='value') + self.low_loss_tab[1, 0].on_click(self.get_resolution_function) + self.low_loss_tab[4, 2].observe(self.parent.info.set_y_scale, names='value') + self.low_loss_tab[4, 0].observe(self._update, names='value') + + def _update(self, ev=0): + self.parent._update(ev) + + if self.low_loss_tab[4, 0].value: + if 'resolution_functions' in self.parent.datasets: + resolution_function = self.get_additional_spectrum('resolution_functions') + self.parent.axis.plot(self.parent.energy_scale, resolution_function, label='resolution_function') + self.parent.axis.plot(self.parent.energy_scale, + self.parent.spectrum -resolution_function, label='difference') + + self.parent.axis.legend() + + def get_additional_spectrum(self, key): + if key not in self.parent.datasets.keys(): + return + + if self.parent.datasets[key].data_type == sidpy.DataType.SPECTRUM: + self.spectrum = self.parent.datasets[key].copy() + else: + image_dims = self.parent.datasets[key].get_dimensions_by_type(sidpy.DimensionType.SPATIAL) + selection = [] + for dim, axis in self.parent.datasets[key]._axes.items(): + # print(dim, axis.dimension_type) + if axis.dimension_type == sidpy.DimensionType.SPATIAL: + if dim == image_dims[0]: + selection.append(slice(self.x, self.x + self.bin_x)) + else: + selection.append(slice(self.y, self.y + self.bin_y)) + + elif axis.dimension_type == sidpy.DimensionType.SPECTRAL: + selection.append(slice(None)) + elif axis.dimension_type == sidpy.DimensionType.CHANNEL: + selection.append(slice(None)) + else: + selection.append(slice(0, 1)) + + self.spectrum = self.parent.datasets[key][tuple(selection)].mean(axis=tuple(image_dims)) + + self.spectrum *= self.parent.y_scale + + return self.spectrum.squeeze() + + def update_ll_dataset(self, value=0): + self.ll_key = self.low_loss_tab[0, 0].value.split(':')[0] + self.parent.set_dataset(self.ll_key) + self.dataset = self.parent.dataset + + + def set_binning(self, value): + if 'SPECTRAL' in self.dataset.data_type.name: + bin_x = self.info_tab[15, 0].value + bin_y = self.info_tab[16, 0].value + self.dataset.view.set_bin([bin_x, bin_y]) + self.datasets[self.key].metadata['experiment']['SI_bin_x'] = bin_x + self.datasets[self.key].metadata['experiment']['SI_bin_y'] = bin_y