From 6e851b494b39f93b87dfde610542a942fc4bd327 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Thu, 31 Mar 2022 17:29:10 +0200 Subject: [PATCH 1/9] Add heatmap, lacks mapping between x-value and 2th --- beamtime/xrd/plot.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index 012e9b8..a073dd6 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -1,3 +1,4 @@ +import seaborn as sns import matplotlib.pyplot as plt from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,AutoMinorLocator) @@ -20,7 +21,7 @@ def plot_diffractogram(data, options={}): # Update options required_options = ['x_vals', 'y_vals', 'ylabel', 'xlabel', 'xunit', 'yunit', 'line', 'scatter', 'xlim', 'ylim', 'normalise', 'offset', 'offset_x', 'offset_y', - 'reflections_plot', 'reflections_indices', 'reflections_data', 'plot_kind', 'palettes', 'interactive', 'rc_params', 'format_params', 'interactive_session_active'] + 'reflections_plot', 'reflections_indices', 'reflections_data', 'heatmap', 'cmap', 'plot_kind', 'palettes', 'interactive', 'rc_params', 'format_params', 'interactive_session_active'] default_options = { 'x_vals': '2th', @@ -37,6 +38,8 @@ def plot_diffractogram(data, options={}): 'reflections_plot': False, # whether to plot reflections as a plot 'reflections_indices': False, # whether to plot the reflection indices 'reflections_data': None, # Should be passed as a list of dictionaries on the form {path: rel_path, reflection_indices: number of indices, colour: [r,g,b], min_alpha: 0-1] + 'heatmap': False, + 'cmap': 'viridis', 'plot_kind': None, 'palettes': [('qualitative', 'Dark2_8')], 'interactive': False, @@ -69,13 +72,20 @@ def plot_diffractogram(data, options={}): data['diffractogram'][index] = diffractogram data['wavelength'][index] = wavelength - else: if not isinstance(data['diffractogram'], list): data['diffractogram'] = [data['diffractogram']] data['wavelength'] = [data['wavelength']] + if options['heatmap']: + data['heatmap'] = [] + for diff in data['diffractogram']: + data['heatmap'].append(np.array(diff['I'])) + + data['heatmap'] = np.array(data['heatmap']) + data['heatmap'] = np.flipud(data['heatmap']) + # Sets the xlim if this has not bee specified if not options['xlim']: options['xlim'] = [diffractogram[options['x_vals']].min(), diffractogram[options['x_vals']].max()] @@ -130,12 +140,17 @@ def plot_diffractogram(data, options={}): colours = btp.generate_colours(['black'], kind='single') - for diffractogram in data['diffractogram']: - if options['line']: - diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax, c=next(colours), zorder=1) - - if options['scatter']: - ax.scatter(x=diffractogram[options['x_vals']], y = diffractogram[options['y_vals']], c=[(1,1,1,0)], edgecolors=[next(colours)], linewidths=plt.rcParams['lines.markeredgewidth'], zorder=2) #, edgecolors=np.array([next(colours)])) + # FIXME Must be changed to map the x-value to the 2th-value somehow + if options['heatmap']: + sns.heatmap(data['heatmap'], cmap=options['cmap']) + + else: + for diffractogram in data['diffractogram']: + if options['line']: + diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax, c=next(colours), zorder=1) + + if options['scatter']: + ax.scatter(x=diffractogram[options['x_vals']], y = diffractogram[options['y_vals']], c=[(1,1,1,0)], edgecolors=[next(colours)], linewidths=plt.rcParams['lines.markeredgewidth'], zorder=2) #, edgecolors=np.array([next(colours)])) @@ -168,7 +183,7 @@ def plot_diffractogram(data, options={}): - return diffractogram, fig, ax + return data['diffractogram'], fig, ax def determine_grid_layout(options): From 567282b80b79d86892e62f144e465f20a5d6f528 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Mon, 4 Apr 2022 14:48:29 +0200 Subject: [PATCH 2/9] Fix bug where extract_folder had no default value --- beamtime/xrd/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beamtime/xrd/io.py b/beamtime/xrd/io.py index dc53b29..729b674 100644 --- a/beamtime/xrd/io.py +++ b/beamtime/xrd/io.py @@ -40,7 +40,7 @@ def integrate_1d(data, options={}, index=0): df: DataFrame contianing 1D diffractogram if option 'return' is True ''' - required_options = ['unit', 'nbins', 'save', 'save_filename', 'save_extension', 'save_folder', 'overwrite'] + required_options = ['unit', 'nbins', 'save', 'save_filename', 'save_extension', 'save_folder', 'overwrite', 'extract_folder'] default_options = { 'unit': '2th_deg', From b0629de9a3dd5e32e49ad59639d1f4ef21c35bf2 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Mon, 4 Apr 2022 14:48:59 +0200 Subject: [PATCH 3/9] Add functions to round up and down to nearest dec --- beamtime/auxillary.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/beamtime/auxillary.py b/beamtime/auxillary.py index 76ec551..68785f7 100644 --- a/beamtime/auxillary.py +++ b/beamtime/auxillary.py @@ -1,4 +1,5 @@ import json +import numpy as np def update_options(options, required_options, default_options): ''' Takes a dictionary of options along with a list of required options and dictionary of default options, and sets all keyval-pairs of options that is not already defined to the default values''' @@ -37,6 +38,18 @@ def swap_values(dict, key1, key2): -def hello_world2(a=1, b=2): +def ceil(a, roundto=1): - print(f'Halla, MAFAKKAS! a = {a} og b = {b}') \ No newline at end of file + fac = 1/roundto + + a = np.ceil(a*fac) / fac + + return a + +def floor(a, roundto=1): + + fac = 1/roundto + + a = np.floor(a*fac) / fac + + return a \ No newline at end of file From 59629fcb615a798a2ef13ad47d83394dfe859d95 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Mon, 4 Apr 2022 14:50:20 +0200 Subject: [PATCH 4/9] Add plotting of heatmaps with true xlim --- beamtime/plotting.py | 2 +- beamtime/xrd/plot.py | 88 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/beamtime/plotting.py b/beamtime/plotting.py index 4e058ac..500f532 100644 --- a/beamtime/plotting.py +++ b/beamtime/plotting.py @@ -182,7 +182,7 @@ def adjust_plot(fig, ax, options): ax.xaxis.set_minor_locator(MultipleLocator(options['x_tick_locators'][1])) - # THIS NEEDS REWORK FOR IT TO FUNCTION PROPERLY! + # FIXME THIS NEEDS REWORK FOR IT TO FUNCTION PROPERLY! if options['xticks']: ax.set_xticks(np.arange(plot_data['start'], plot_data['end']+1)) ax.set_xticklabels(options['xticks']) diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index a073dd6..d2b7b51 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -72,23 +72,20 @@ def plot_diffractogram(data, options={}): data['diffractogram'][index] = diffractogram data['wavelength'][index] = wavelength + # Sets the xlim if this has not bee specified + if not options['xlim']: + options['xlim'] = [data['diffractogram'][0][options['x_vals']].min(), data['diffractogram'][0][options['x_vals']].max()] + + + if options['heatmap']: + data['heatmap'], data['heatmap_xticks'], data['heatmap_xticklabels'] = generate_heatmap(data=data, options=options) + options['xlim'] = options['heatmap_xlim'] else: if not isinstance(data['diffractogram'], list): data['diffractogram'] = [data['diffractogram']] data['wavelength'] = [data['wavelength']] - if options['heatmap']: - data['heatmap'] = [] - for diff in data['diffractogram']: - data['heatmap'].append(np.array(diff['I'])) - - data['heatmap'] = np.array(data['heatmap']) - data['heatmap'] = np.flipud(data['heatmap']) - - # Sets the xlim if this has not bee specified - if not options['xlim']: - options['xlim'] = [diffractogram[options['x_vals']].min(), diffractogram[options['x_vals']].max()] if options['interactive_session_active']: @@ -142,7 +139,10 @@ def plot_diffractogram(data, options={}): # FIXME Must be changed to map the x-value to the 2th-value somehow if options['heatmap']: - sns.heatmap(data['heatmap'], cmap=options['cmap']) + sns.heatmap(data['heatmap'], cmap=options['cmap'], cbar=False, ax=ax) + ax.set_xticks(data['heatmap_xticks']) + ax.set_xticklabels(data['heatmap_xticklabels']) + ax.tick_params(axis='x', which='minor', bottom=False, top=False) else: for diffractogram in data['diffractogram']: @@ -186,6 +186,68 @@ def plot_diffractogram(data, options={}): return data['diffractogram'], fig, ax + +def generate_heatmap(data, options={}): + + required_options = ['x_tick_locators'] + + default_options = { + 'x_tick_locators': [0.5, 0.1] + } + + options = aux.update_options(options=options, required_options=required_options, default_options=default_options) + + twotheta = [] + intensities = [] + scans = [] + + for i, d in enumerate(data['diffractogram']): + twotheta = np.append(twotheta, d['2th'].to_numpy()) + intensities = np.append(intensities, d['I'].to_numpy()) + scans = np.append(scans, np.full(len(d['2th'].to_numpy()), int(i))) + + + # Generate ticks and xtick-labels + twotheta_max = data['diffractogram'][0]['2th'].max() + twotheta_min = data['diffractogram'][0]['2th'].min() + twotheta_span = twotheta_max - twotheta_min + ndatapoints = len(data['diffractogram'][0]['2th']) + steps = twotheta_span / ndatapoints + + twotheta_label_max = aux.floor(twotheta_max, roundto=options['x_tick_locators'][0]) + twotheta_label_min = aux.ceil(twotheta_min, roundto=options['x_tick_locators'][0]) + label_steps = (twotheta_label_max - twotheta_label_min)/options['x_tick_locators'][0] + + + + xtick_labels = np.linspace(twotheta_label_min, twotheta_label_max, num=int(label_steps)+1) + + options['x_tick_locators'] = None + + xticks = [] + for tick in xtick_labels: + xticks.append((tick - twotheta_min)/steps) + + heatmap = pd.DataFrame({'2th': twotheta, 'scan': scans, 'I': intensities}) + heatmap = heatmap.reset_index().pivot_table(index='scan', columns='2th', values='I') + + options['heatmap_xlim'] = [(options['xlim'][0] - twotheta_min)/steps, (options['xlim'][1] - twotheta_min)/steps] + + + print(xticks, xtick_labels) + + + return heatmap, xticks, xtick_labels + + + + + + + +# #results = np.transpose(np.vstack([twotheta, scans, intensities])) + + def determine_grid_layout(options): @@ -202,6 +264,8 @@ def determine_grid_layout(options): + + def plot_diffractogram_interactive(data, options): From 5541f44a58b4cbc96ba2c55f3ce1b16fcc255bb4 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Mon, 4 Apr 2022 16:47:01 +0200 Subject: [PATCH 5/9] Add automatic change of xlim range with heatmaps --- beamtime/xrd/plot.py | 107 ++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index d2b7b51..df17e8d 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -76,9 +76,9 @@ def plot_diffractogram(data, options={}): if not options['xlim']: options['xlim'] = [data['diffractogram'][0][options['x_vals']].min(), data['diffractogram'][0][options['x_vals']].max()] - - if options['heatmap']: - data['heatmap'], data['heatmap_xticks'], data['heatmap_xticklabels'] = generate_heatmap(data=data, options=options) + # Generate heatmap data + data['heatmap'], data['heatmap_xticks'], data['heatmap_xticklabels'] = generate_heatmap(data=data, options=options) + if options['heatmap']: options['xlim'] = options['heatmap_xlim'] else: @@ -136,12 +136,10 @@ def plot_diffractogram(data, options={}): else: colours = btp.generate_colours(['black'], kind='single') - - # FIXME Must be changed to map the x-value to the 2th-value somehow if options['heatmap']: sns.heatmap(data['heatmap'], cmap=options['cmap'], cbar=False, ax=ax) - ax.set_xticks(data['heatmap_xticks']) - ax.set_xticklabels(data['heatmap_xticklabels']) + ax.set_xticks(data['heatmap_xticks'][options['x_vals']]) + ax.set_xticklabels(data['heatmap_xticklabels'][options['x_vals']]) ax.tick_params(axis='x', which='minor', bottom=False, top=False) else: @@ -176,7 +174,7 @@ def plot_diffractogram(data, options={}): if options['interactive_session_active']: - btp.update_widgets(options=options) + update_widgets(options=options) @@ -207,37 +205,52 @@ def generate_heatmap(data, options={}): scans = np.append(scans, np.full(len(d['2th'].to_numpy()), int(i))) - # Generate ticks and xtick-labels - twotheta_max = data['diffractogram'][0]['2th'].max() - twotheta_min = data['diffractogram'][0]['2th'].min() - twotheta_span = twotheta_max - twotheta_min + heatmap = pd.DataFrame({'2th': twotheta, 'scan': scans, 'I': intensities}) + xrd.io.translate_wavelengths(data=heatmap, wavelength=data['wavelength'][0]) + min_dict = {'2th': heatmap['2th'].min(), '2th_cuka': heatmap['2th_cuka'].min(), '2th_moka': heatmap['2th_moka'].min(), + 'q': heatmap['q'].min(), 'q2': heatmap['q2'].min(), 'q4': heatmap['q4'].min(), '1/d': heatmap['1/d'].min()} + + max_dict = {'2th': heatmap['2th'].max(), '2th_cuka': heatmap['2th_cuka'].max(), '2th_moka': heatmap['2th_moka'].max(), + 'q': heatmap['q'].max(), 'q2': heatmap['q2'].max(), 'q4': heatmap['q4'].max(), '1/d': heatmap['1/d'].max()} + + ndatapoints = len(data['diffractogram'][0]['2th']) - steps = twotheta_span / ndatapoints - twotheta_label_max = aux.floor(twotheta_max, roundto=options['x_tick_locators'][0]) - twotheta_label_min = aux.ceil(twotheta_min, roundto=options['x_tick_locators'][0]) - label_steps = (twotheta_label_max - twotheta_label_min)/options['x_tick_locators'][0] + xlims = [0, ndatapoints] + xticks = {} + xticklabels = {} - + for xval in min_dict.keys(): + + # Add xticks labels + + label_max = aux.floor(max_dict[xval], roundto=options['x_tick_locators'][0]) + label_min = aux.ceil(min_dict[xval], roundto=options['x_tick_locators'][0]) + label_steps = (label_max - label_min)/options['x_tick_locators'][0] + + xticklabels[xval] = np.linspace(label_min, label_max, num=int(label_steps)+1) + + # Add xticks + xval_span = max_dict[xval] - min_dict[xval] + steps = xval_span / ndatapoints + + + xticks_xval = [] + + for tick in xticklabels[xval]: + xticks_xval.append((tick-min_dict[xval])/steps) + + xticks[xval] = xticks_xval - xtick_labels = np.linspace(twotheta_label_min, twotheta_label_max, num=int(label_steps)+1) options['x_tick_locators'] = None - xticks = [] - for tick in xtick_labels: - xticks.append((tick - twotheta_min)/steps) - - heatmap = pd.DataFrame({'2th': twotheta, 'scan': scans, 'I': intensities}) heatmap = heatmap.reset_index().pivot_table(index='scan', columns='2th', values='I') - options['heatmap_xlim'] = [(options['xlim'][0] - twotheta_min)/steps, (options['xlim'][1] - twotheta_min)/steps] + options['heatmap_xlim'] = xlims - print(xticks, xtick_labels) - - - return heatmap, xticks, xtick_labels + return heatmap, xticks, xticklabels @@ -269,9 +282,9 @@ def determine_grid_layout(options): def plot_diffractogram_interactive(data, options): - minmax = {'2th': [None, None], '2th_cuka': [None, None], '2th_moka': [None, None], 'd': [None, None], '1/d': [None, None], 'q': [None, None], 'q2': [None, None], 'q4': [None, None]} + minmax = {'2th': [None, None], '2th_cuka': [None, None], '2th_moka': [None, None], 'd': [None, None], '1/d': [None, None], 'q': [None, None], 'q2': [None, None], 'q4': [None, None], 'heatmap': [None, None]} - update_minmax(minmax, data) + update_minmax(minmax=minmax, data=data, options=options) ymin, ymax = None, None for index, diffractogram in enumerate(data['diffractogram']): @@ -288,8 +301,6 @@ def plot_diffractogram_interactive(data, options): ymax = ymax*5 - - options['widgets'] = { 'xlim': { 'w': widgets.FloatRangeSlider(value=[minmax['2th'][0], minmax['2th'][1]], min=minmax['2th'][0], max=minmax['2th'][1], step=0.5, layout=widgets.Layout(width='95%')), @@ -301,17 +312,18 @@ def plot_diffractogram_interactive(data, options): '1/d_default': {'min': minmax['1/d'][0], 'max': minmax['1/d'][1], 'value': [minmax['1/d'][0], minmax['1/d'][1]], 'step': 0.5}, 'q_default': {'min': minmax['q'][0], 'max': minmax['q'][1], 'value': [minmax['q'][0], minmax['q'][1]], 'step': 0.5}, 'q2_default': {'min': minmax['q2'][0], 'max': minmax['q2'][1], 'value': [minmax['q2'][0], minmax['q2'][1]], 'step': 0.5}, - 'q4_default': {'min': minmax['q4'][0], 'max': minmax['q4'][1], 'value': [minmax['q4'][0], minmax['q4'][1]], 'step': 0.5} + 'q4_default': {'min': minmax['q4'][0], 'max': minmax['q4'][1], 'value': [minmax['q4'][0], minmax['q4'][1]], 'step': 0.5}, + 'heatmap_default': {'min': minmax['heatmap'][0], 'max': minmax['heatmap'][1], 'value': [minmax['heatmap'][0], minmax['heatmap'][1]], 'step': 10} } } - if options['reflections_data']: w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_diffractogram), data=widgets.fixed(data), options=widgets.fixed(options), scatter=widgets.ToggleButton(value=False), line=widgets.ToggleButton(value=True), reflections_plot=widgets.ToggleButton(value=True), reflections_indices=widgets.ToggleButton(value=False), + heatmap=widgets.ToggleButton(value=options['heatmap']), x_vals=widgets.Dropdown(options=['2th', 'd', '1/d', 'q', 'q2', 'q4', '2th_cuka', '2th_moka'], value='2th', description='X-values'), xlim=options['widgets']['xlim']['w'], ylim=widgets.FloatRangeSlider(value=[ymin_start, ymax_start], min=ymin, max=ymax, step=0.5, layout=widgets.Layout(width='95%')), @@ -329,7 +341,7 @@ def plot_diffractogram_interactive(data, options): display(w) -def update_minmax(minmax, data): +def update_minmax(minmax, data, options={}): ''' Finds minimum and maximum values of each column and updates the minmax dictionary to contain the correct values. Input: @@ -351,15 +363,38 @@ def update_minmax(minmax, data): minmax['q'][0], minmax['q'][1] = data['diffractogram'][min_index]['q'].min(), data['diffractogram'][max_index]['q'].max() minmax['q2'][0], minmax['q2'][1] = data['diffractogram'][min_index]['q2'].min(), data['diffractogram'][max_index]['q2'].max() minmax['q4'][0], minmax['q4'][1] = data['diffractogram'][min_index]['q4'].min(), data['diffractogram'][max_index]['q4'].max() + minmax['heatmap'] = options['heatmap_xlim'] + + def update_widgets(options): for widget in options['widgets'].values(): - if widget['state'] != options['x_vals']: + if options['heatmap'] and (widget['state'] != 'heatmap'): + setattr(widget['w'], 'min', widget['heatmap_default']['min']) + setattr(widget['w'], 'max', widget['heatmap_default']['max']) + setattr(widget['w'], 'value', widget['heatmap_default']['value']) + setattr(widget['w'], 'step', widget['heatmap_default']['step']) + + widget['state'] = 'heatmap' + + elif not options['heatmap'] and (widget['state'] != options['x_vals']): for arg in widget[f'{options["x_vals"]}_default']: + + # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first + if arg == 'min': + if widget[f'{options["x_vals"]}_default']['min'] > getattr(widget['w'], 'max'): + setattr(widget['w'], 'max', widget[f'{options["x_vals"]}_default']['max']) + + elif arg == 'max': + if widget[f'{options["x_vals"]}_default']['max'] < getattr(widget['w'], 'min'): + setattr(widget['w'], 'min', widget[f'{options["x_vals"]}_default']['min']) + + setattr(widget['w'], arg, widget[f'{options["x_vals"]}_default'][arg]) + widget['state'] = options['x_vals'] From c0449f2e183d17f684d0906791e9a2b9e82d52f7 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Tue, 5 Apr 2022 13:52:27 +0200 Subject: [PATCH 6/9] Correct switch of ylim between diff and heatmap --- beamtime/xrd/plot.py | 199 +++++++++++++++++++++++++++++-------------- 1 file changed, 135 insertions(+), 64 deletions(-) diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index df17e8d..c97dabe 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -176,9 +176,6 @@ def plot_diffractogram(data, options={}): if options['interactive_session_active']: update_widgets(options=options) - - - return data['diffractogram'], fig, ax @@ -282,38 +279,51 @@ def determine_grid_layout(options): def plot_diffractogram_interactive(data, options): - minmax = {'2th': [None, None], '2th_cuka': [None, None], '2th_moka': [None, None], 'd': [None, None], '1/d': [None, None], 'q': [None, None], 'q2': [None, None], 'q4': [None, None], 'heatmap': [None, None]} + xminmax = {'2th': [None, None], '2th_cuka': [None, None], '2th_moka': [None, None], 'd': [None, None], '1/d': [None, None], 'q': [None, None], 'q2': [None, None], 'q4': [None, None], 'heatmap': [None, None], 'start': [None, None, None, None]} + yminmax = {'diff': [None, None, None, None], 'heatmap': [None, None], 'start': [None, None, None, None]} - update_minmax(minmax=minmax, data=data, options=options) - - ymin, ymax = None, None - for index, diffractogram in enumerate(data['diffractogram']): - if not ymin or (ymin > (diffractogram['I'].min())): #+index*options['offset_y'])): - ymin = diffractogram['I'].min()#+index*options['offset_y'] - - if not ymax or (ymax < (diffractogram['I'].max())):#+index*options['offset_y'])): - ymax = diffractogram['I'].max()#+index*options['offset_y'] + update_xminmax(xminmax=xminmax, data=data, options=options) + update_yminmax(yminmax=yminmax, data=data, options=options) - ymin_start = ymin - 0.1*ymax - ymax_start = ymax+0.2*ymax - ymin = ymin - 5*ymax - ymax = ymax*5 + + # Get start values for ylim slider based on choice (FIXME This can be impleneted into update_yminmax). Can also make a 'start' item that stores the start values, instead of having 4 items in 'diff' as it is now. + if options['heatmap']: + ymin = yminmax['heatmap'][0] + ymax = yminmax['heatmap'][1] + ymin_start = yminmax['heatmap'][0] + ymax_start = yminmax['heatmap'][1] + + elif not options['heatmap']: + ymin = yminmax['diff'][0] + ymax = yminmax['diff'][1] + ymin_start = yminmax['diff'][2] + ymax_start = yminmax['diff'][3] + + + # FIXME The start values for xlim should probably also be decided by initial value of x_vals, and can likewise be implemented in update_xminmax() + options['widgets'] = { 'xlim': { - 'w': widgets.FloatRangeSlider(value=[minmax['2th'][0], minmax['2th'][1]], min=minmax['2th'][0], max=minmax['2th'][1], step=0.5, layout=widgets.Layout(width='95%')), - 'state': '2th', - '2th_default': {'min': minmax['2th'][0], 'max': minmax['2th'][1], 'value': [minmax['2th'][0], minmax['2th'][1]], 'step': 0.5}, - '2th_cuka_default': {'min': minmax['2th_cuka'][0], 'max': minmax['2th_cuka'][1], 'value': [minmax['2th_cuka'][0], minmax['2th_cuka'][1]], 'step': 0.5}, - '2th_moka_default': {'min': minmax['2th_moka'][0], 'max': minmax['2th_moka'][1], 'value': [minmax['2th_moka'][0], minmax['2th_moka'][1]], 'step': 0.5}, - 'd_default': {'min': minmax['d'][0], 'max': minmax['d'][1], 'value': [minmax['d'][0], minmax['d'][1]], 'step': 0.5}, - '1/d_default': {'min': minmax['1/d'][0], 'max': minmax['1/d'][1], 'value': [minmax['1/d'][0], minmax['1/d'][1]], 'step': 0.5}, - 'q_default': {'min': minmax['q'][0], 'max': minmax['q'][1], 'value': [minmax['q'][0], minmax['q'][1]], 'step': 0.5}, - 'q2_default': {'min': minmax['q2'][0], 'max': minmax['q2'][1], 'value': [minmax['q2'][0], minmax['q2'][1]], 'step': 0.5}, - 'q4_default': {'min': minmax['q4'][0], 'max': minmax['q4'][1], 'value': [minmax['q4'][0], minmax['q4'][1]], 'step': 0.5}, - 'heatmap_default': {'min': minmax['heatmap'][0], 'max': minmax['heatmap'][1], 'value': [minmax['heatmap'][0], minmax['heatmap'][1]], 'step': 10} + 'w': widgets.FloatRangeSlider(value=[xminmax['start'][2], xminmax['start'][3]], min=xminmax['start'][0], max=xminmax['start'][1], step=0.5, layout=widgets.Layout(width='95%')), + 'state': options['x_vals'], + '2th_default': {'min': xminmax['2th'][0], 'max': xminmax['2th'][1], 'value': [xminmax['2th'][0], xminmax['2th'][1]], 'step': 0.5}, + '2th_cuka_default': {'min': xminmax['2th_cuka'][0], 'max': xminmax['2th_cuka'][1], 'value': [xminmax['2th_cuka'][0], xminmax['2th_cuka'][1]], 'step': 0.5}, + '2th_moka_default': {'min': xminmax['2th_moka'][0], 'max': xminmax['2th_moka'][1], 'value': [xminmax['2th_moka'][0], xminmax['2th_moka'][1]], 'step': 0.5}, + 'd_default': {'min': xminmax['d'][0], 'max': xminmax['d'][1], 'value': [xminmax['d'][0], xminmax['d'][1]], 'step': 0.5}, + '1/d_default': {'min': xminmax['1/d'][0], 'max': xminmax['1/d'][1], 'value': [xminmax['1/d'][0], xminmax['1/d'][1]], 'step': 0.5}, + 'q_default': {'min': xminmax['q'][0], 'max': xminmax['q'][1], 'value': [xminmax['q'][0], xminmax['q'][1]], 'step': 0.5}, + 'q2_default': {'min': xminmax['q2'][0], 'max': xminmax['q2'][1], 'value': [xminmax['q2'][0], xminmax['q2'][1]], 'step': 0.5}, + 'q4_default': {'min': xminmax['q4'][0], 'max': xminmax['q4'][1], 'value': [xminmax['q4'][0], xminmax['q4'][1]], 'step': 0.5}, + 'heatmap_default': {'min': xminmax['heatmap'][0], 'max': xminmax['heatmap'][1], 'value': [xminmax['heatmap'][0], xminmax['heatmap'][1]], 'step': 10} + }, + 'ylim': { + 'w': widgets.FloatRangeSlider(value=[yminmax['start'][2], yminmax['start'][3]], min=yminmax['start'][0], max=yminmax['start'][1], step=0.5, layout=widgets.Layout(width='95%')), + 'state': 'heatmap' if options['heatmap'] else 'diff', + 'diff_default': {'min': yminmax['diff'][0], 'max': yminmax['diff'][1], 'value': [yminmax['diff'][2], yminmax['diff'][3]], 'step': 0.1}, + 'heatmap_default': {'min': yminmax['heatmap'][0], 'max': yminmax['heatmap'][1], 'value': [yminmax['heatmap'][0], yminmax['heatmap'][1]], 'step': 0.1} } } @@ -326,7 +336,7 @@ def plot_diffractogram_interactive(data, options): heatmap=widgets.ToggleButton(value=options['heatmap']), x_vals=widgets.Dropdown(options=['2th', 'd', '1/d', 'q', 'q2', 'q4', '2th_cuka', '2th_moka'], value='2th', description='X-values'), xlim=options['widgets']['xlim']['w'], - ylim=widgets.FloatRangeSlider(value=[ymin_start, ymax_start], min=ymin, max=ymax, step=0.5, layout=widgets.Layout(width='95%')), + ylim=options['widgets']['ylim']['w'], offset_y=widgets.BoundedFloatText(value=options['offset_y'], min=-5, max=5, step=0.01), offset_x=widgets.BoundedFloatText(value=options['offset_x'], min=-1, max=1, step=0.01) ) @@ -341,61 +351,122 @@ def plot_diffractogram_interactive(data, options): display(w) -def update_minmax(minmax, data, options={}): +def update_xminmax(xminmax, data, options={}): ''' Finds minimum and maximum values of each column and updates the minmax dictionary to contain the correct values. Input: minmax (dict): contains ''' for index, diffractogram in enumerate(data['diffractogram']): - if not minmax['2th'][0] or diffractogram['2th'].min() < minmax['2th'][0]: - minmax['2th'][0] = diffractogram['2th'].min() + if not xminmax['2th'][0] or diffractogram['2th'].min() < xminmax['2th'][0]: + xminmax['2th'][0] = diffractogram['2th'].min() min_index = index - if not minmax['2th'][1] or diffractogram['2th'].max() > minmax['2th'][1]: - minmax['2th'][1] = diffractogram['2th'].max() + if not xminmax['2th'][1] or diffractogram['2th'].max() > xminmax['2th'][1]: + xminmax['2th'][1] = diffractogram['2th'].max() max_index = index - minmax['2th_cuka'][0], minmax['2th_cuka'][1] = data['diffractogram'][min_index]['2th_cuka'].min(), data['diffractogram'][max_index]['2th_cuka'].max() - minmax['2th_moka'][0], minmax['2th_moka'][1] = data['diffractogram'][min_index]['2th_moka'].min(), data['diffractogram'][max_index]['2th_moka'].max() - minmax['d'][0], minmax['d'][1] = data['diffractogram'][max_index]['d'].min(), data['diffractogram'][min_index]['d'].max() # swapped, intended - minmax['1/d'][0], minmax['1/d'][1] = data['diffractogram'][min_index]['1/d'].min(), data['diffractogram'][max_index]['1/d'].max() - minmax['q'][0], minmax['q'][1] = data['diffractogram'][min_index]['q'].min(), data['diffractogram'][max_index]['q'].max() - minmax['q2'][0], minmax['q2'][1] = data['diffractogram'][min_index]['q2'].min(), data['diffractogram'][max_index]['q2'].max() - minmax['q4'][0], minmax['q4'][1] = data['diffractogram'][min_index]['q4'].min(), data['diffractogram'][max_index]['q4'].max() - minmax['heatmap'] = options['heatmap_xlim'] + xminmax['2th_cuka'][0], xminmax['2th_cuka'][1] = data['diffractogram'][min_index]['2th_cuka'].min(), data['diffractogram'][max_index]['2th_cuka'].max() + xminmax['2th_moka'][0], xminmax['2th_moka'][1] = data['diffractogram'][min_index]['2th_moka'].min(), data['diffractogram'][max_index]['2th_moka'].max() + xminmax['d'][0], xminmax['d'][1] = data['diffractogram'][max_index]['d'].min(), data['diffractogram'][min_index]['d'].max() # swapped, intended + xminmax['1/d'][0], xminmax['1/d'][1] = data['diffractogram'][min_index]['1/d'].min(), data['diffractogram'][max_index]['1/d'].max() + xminmax['q'][0], xminmax['q'][1] = data['diffractogram'][min_index]['q'].min(), data['diffractogram'][max_index]['q'].max() + xminmax['q2'][0], xminmax['q2'][1] = data['diffractogram'][min_index]['q2'].min(), data['diffractogram'][max_index]['q2'].max() + xminmax['q4'][0], xminmax['q4'][1] = data['diffractogram'][min_index]['q4'].min(), data['diffractogram'][max_index]['q4'].max() + xminmax['heatmap'] = options['heatmap_xlim'] + + + xminmax['start'][0], xminmax['start'][1] = xminmax[options['x_vals']][0], xminmax[options['x_vals']][1] + xminmax['start'][2], xminmax['start'][3] = xminmax[options['x_vals']][0], xminmax[options['x_vals']][1] + + +def update_yminmax(yminmax: dict, data, options={}): + + for index, diffractogram in enumerate(data['diffractogram']): + if not yminmax['diff'][0] or (yminmax['diff'][0] > (diffractogram['I'].min())): + yminmax['diff'][0] = diffractogram['I'].min() + + if not yminmax['diff'][1] or (yminmax['diff'][1] < (diffractogram['I'].max())): + yminmax['diff'][1] = diffractogram['I'].max() + + + # Set start values of ymin and ymax to be slightly below lowest data points and slightly above highest data points to give some whitespace around the plot + yminmax['diff'][2] = yminmax['diff'][0] - 0.1*yminmax['diff'][1] + yminmax['diff'][3] = yminmax['diff'][1] + 0.2*yminmax['diff'][1] + + # Allow for adjustment up to five times ymax above and below data + yminmax['diff'][0] = yminmax['diff'][0] - 5*yminmax['diff'][1] + yminmax['diff'][1] = yminmax['diff'][1]*5 + + + yminmax['heatmap'][0] = 0 + yminmax['heatmap'][1] = data['heatmap'].shape[0] + + + if options['heatmap']: + yminmax['start'][0], yminmax['start'][1] = yminmax['heatmap'][0], yminmax['heatmap'][1] + yminmax['start'][2], yminmax['start'][3] = yminmax['heatmap'][0], yminmax['heatmap'][1] + + else: + # The third and fourth index are different here to not be zoomed completely out to begin with. + yminmax['start'][0], yminmax['start'][1] = yminmax['diff'][0], yminmax['diff'][1] + yminmax['start'][2], yminmax['start'][3] = yminmax['diff'][2], yminmax['diff'][3] + def update_widgets(options): - for widget in options['widgets'].values(): + for widget, attr in options['widgets'].items(): - if options['heatmap'] and (widget['state'] != 'heatmap'): - setattr(widget['w'], 'min', widget['heatmap_default']['min']) - setattr(widget['w'], 'max', widget['heatmap_default']['max']) - setattr(widget['w'], 'value', widget['heatmap_default']['value']) - setattr(widget['w'], 'step', widget['heatmap_default']['step']) + if widget == 'xlim': + + if options['heatmap'] and (attr['state'] != 'heatmap'): + setattr(attr['w'], 'min', attr['heatmap_default']['min']) + setattr(attr['w'], 'max', attr['heatmap_default']['max']) + setattr(attr['w'], 'value', attr['heatmap_default']['value']) + setattr(attr['w'], 'step', attr['heatmap_default']['step']) + + attr['state'] = 'heatmap' + + elif not options['heatmap'] and (attr['state'] != options['x_vals']): + for arg in attr[f'{options["x_vals"]}_default']: + + # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first + if arg == 'min': + if attr[f'{options["x_vals"]}_default']['min'] > getattr(attr['w'], 'max'): + setattr(attr['w'], 'max', attr[f'{options["x_vals"]}_default']['max']) + + elif arg == 'max': + if attr[f'{options["x_vals"]}_default']['max'] < getattr(attr['w'], 'min'): + setattr(attr['w'], 'min', attr[f'{options["x_vals"]}_default']['min']) - widget['state'] = 'heatmap' - - elif not options['heatmap'] and (widget['state'] != options['x_vals']): - for arg in widget[f'{options["x_vals"]}_default']: - # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first - if arg == 'min': - if widget[f'{options["x_vals"]}_default']['min'] > getattr(widget['w'], 'max'): - setattr(widget['w'], 'max', widget[f'{options["x_vals"]}_default']['max']) + setattr(attr['w'], arg, attr[f'{options["x_vals"]}_default'][arg]) - elif arg == 'max': - if widget[f'{options["x_vals"]}_default']['max'] < getattr(widget['w'], 'min'): - setattr(widget['w'], 'min', widget[f'{options["x_vals"]}_default']['min']) + + attr['state'] = options['x_vals'] + + elif widget == 'ylim': + state = 'heatmap' if options['heatmap'] else 'diff' + + if attr['state'] != state: + + for arg in attr[f'{state}_default']: + # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first + if arg == 'min': + if attr[f'{state}_default']['min'] > getattr(attr['w'], 'max'): + setattr(attr['w'], 'max', attr[f'{state}_default']['max']) + + elif arg == 'max': + if attr[f'{state}_default']['max'] < getattr(attr['w'], 'min'): + setattr(attr['w'], 'min', attr[f'{state}_default']['min']) + + + setattr(attr['w'], arg, attr[f'{state}_default'][arg]) + + attr['state'] = state - - setattr(widget['w'], arg, widget[f'{options["x_vals"]}_default'][arg]) - - - widget['state'] = options['x_vals'] From 876e0f8d3d2759a762dbaf58c317e41fbf50c4bc Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Tue, 5 Apr 2022 16:12:19 +0200 Subject: [PATCH 7/9] Allow rescaling ylim with interactive diff plot --- beamtime/xrd/io.py | 11 ++- beamtime/xrd/plot.py | 161 ++++++++++++++++++++++++++++++------------- 2 files changed, 122 insertions(+), 50 deletions(-) diff --git a/beamtime/xrd/io.py b/beamtime/xrd/io.py index 729b674..910811b 100644 --- a/beamtime/xrd/io.py +++ b/beamtime/xrd/io.py @@ -358,9 +358,18 @@ def read_data(data, options={}, index=0): def apply_offset(diffractogram, wavelength, index, options): - options['current_offset_y'] = options['offset_y'] + if 'current_offset_y' not in options.keys(): + options['current_offset_y'] = options['offset_y'] + else: + if options['current_offset_y'] != options['offset_y']: + options['offset_change'] = True + + options['current_offset_y'] = options['offset_y'] + options['current_offset_x'] = options['offset_x'] + + #Apply offset along y-axis diffractogram['I'] = diffractogram['I_org'] # Reset intensities diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index c97dabe..9012b4a 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -20,7 +20,7 @@ def plot_diffractogram(data, options={}): data (dict): Must include path = string to diffractogram data, and plot_kind = (recx, beamline, image)''' # Update options - required_options = ['x_vals', 'y_vals', 'ylabel', 'xlabel', 'xunit', 'yunit', 'line', 'scatter', 'xlim', 'ylim', 'normalise', 'offset', 'offset_x', 'offset_y', + required_options = ['x_vals', 'y_vals', 'ylabel', 'xlabel', 'xunit', 'yunit', 'line', 'scatter', 'xlim', 'ylim', 'normalise', 'offset', 'offset_x', 'offset_y', 'offset_change', 'reflections_plot', 'reflections_indices', 'reflections_data', 'heatmap', 'cmap', 'plot_kind', 'palettes', 'interactive', 'rc_params', 'format_params', 'interactive_session_active'] default_options = { @@ -33,6 +33,7 @@ def plot_diffractogram(data, options={}): 'offset': True, 'offset_x': 0, 'offset_y': 1, + 'offset_change': False, 'line': True, # whether or not to plot diffractogram as a line plot 'scatter': False, # whether or not to plot individual data points 'reflections_plot': False, # whether to plot reflections as a plot @@ -53,6 +54,7 @@ def plot_diffractogram(data, options={}): default_options['offset_y'] = 0.05 options = aux.update_options(options=options, required_options=required_options, default_options=default_options) + options['current_offset_y'] = options['offset_y'] # Convert data['path'] to list to allow iteration over this to accommodate both single and multiple diffractograms if not isinstance(data['path'], list): @@ -174,7 +176,8 @@ def plot_diffractogram(data, options={}): if options['interactive_session_active']: - update_widgets(options=options) + options['current_y_offset'] = options['widget'].kwargs['offset_y'] + update_widgets(data=data, options=options) @@ -213,7 +216,7 @@ def generate_heatmap(data, options={}): ndatapoints = len(data['diffractogram'][0]['2th']) - xlims = [0, ndatapoints] + xlims = [0, ndatapoints, 0, ndatapoints] # 0: xmin, 1: xmax, 2: xmin_start, 3: xmax_start xticks = {} xticklabels = {} @@ -279,13 +282,18 @@ def determine_grid_layout(options): def plot_diffractogram_interactive(data, options): - xminmax = {'2th': [None, None], '2th_cuka': [None, None], '2th_moka': [None, None], 'd': [None, None], '1/d': [None, None], 'q': [None, None], 'q2': [None, None], 'q4': [None, None], 'heatmap': [None, None], 'start': [None, None, None, None]} - yminmax = {'diff': [None, None, None, None], 'heatmap': [None, None], 'start': [None, None, None, None]} + # Format here is xminmax[0]: xmin, xminmax[1]: xmax, xminmax[2]: xmin_start, xminmax[3]: xmax_start, where "_start" denotes starting value of the slider + xminmax = { '2th': [None, None, None, None], '2th_cuka': [None, None, None, None], '2th_moka': [None, None, None, None], + 'd': [None, None, None, None], '1/d': [None, None, None, None], + 'q': [None, None, None, None], 'q2': [None, None, None, None], 'q4': [None, None, None, None], + 'heatmap': [None, None, None, None], 'start': [None, None, None, None]} + + yminmax = { 'diff': [None, None, None, None], 'heatmap': [None, None, None, None], 'start': [None, None, None, None]} update_xminmax(xminmax=xminmax, data=data, options=options) update_yminmax(yminmax=yminmax, data=data, options=options) - + options['xminmax'], options['yminmax'] = xminmax, yminmax # Get start values for ylim slider based on choice (FIXME This can be impleneted into update_yminmax). Can also make a 'start' item that stores the start values, instead of having 4 items in 'diff' as it is now. if options['heatmap']: @@ -337,8 +345,8 @@ def plot_diffractogram_interactive(data, options): x_vals=widgets.Dropdown(options=['2th', 'd', '1/d', 'q', 'q2', 'q4', '2th_cuka', '2th_moka'], value='2th', description='X-values'), xlim=options['widgets']['xlim']['w'], ylim=options['widgets']['ylim']['w'], - offset_y=widgets.BoundedFloatText(value=options['offset_y'], min=-5, max=5, step=0.01), - offset_x=widgets.BoundedFloatText(value=options['offset_x'], min=-1, max=1, step=0.01) + offset_y=widgets.BoundedFloatText(value=options['offset_y'], min=-5, max=5, step=0.01, description='offset_y'), + offset_x=widgets.BoundedFloatText(value=options['offset_x'], min=-1, max=1, step=0.01, description='offset_x') ) else: @@ -348,6 +356,8 @@ def plot_diffractogram_interactive(data, options): xlim=options['widgets']['xlim']['w']) + options['widget'] = w + display(w) @@ -357,7 +367,9 @@ def update_xminmax(xminmax, data, options={}): Input: minmax (dict): contains ''' + xminmax['2th'] = [None, None, None, None] for index, diffractogram in enumerate(data['diffractogram']): + if not xminmax['2th'][0] or diffractogram['2th'].min() < xminmax['2th'][0]: xminmax['2th'][0] = diffractogram['2th'].min() min_index = index @@ -366,23 +378,43 @@ def update_xminmax(xminmax, data, options={}): xminmax['2th'][1] = diffractogram['2th'].max() max_index = index - xminmax['2th_cuka'][0], xminmax['2th_cuka'][1] = data['diffractogram'][min_index]['2th_cuka'].min(), data['diffractogram'][max_index]['2th_cuka'].max() - xminmax['2th_moka'][0], xminmax['2th_moka'][1] = data['diffractogram'][min_index]['2th_moka'].min(), data['diffractogram'][max_index]['2th_moka'].max() - xminmax['d'][0], xminmax['d'][1] = data['diffractogram'][max_index]['d'].min(), data['diffractogram'][min_index]['d'].max() # swapped, intended - xminmax['1/d'][0], xminmax['1/d'][1] = data['diffractogram'][min_index]['1/d'].min(), data['diffractogram'][max_index]['1/d'].max() - xminmax['q'][0], xminmax['q'][1] = data['diffractogram'][min_index]['q'].min(), data['diffractogram'][max_index]['q'].max() - xminmax['q2'][0], xminmax['q2'][1] = data['diffractogram'][min_index]['q2'].min(), data['diffractogram'][max_index]['q2'].max() - xminmax['q4'][0], xminmax['q4'][1] = data['diffractogram'][min_index]['q4'].min(), data['diffractogram'][max_index]['q4'].max() - xminmax['heatmap'] = options['heatmap_xlim'] + + xminmax['2th'][2], xminmax['2th'][3] = xminmax['2th'][0], xminmax['2th'][1] + + xminmax['2th_cuka'][0], xminmax['2th_cuka'][1] = data['diffractogram'][min_index]['2th_cuka'].min(), data['diffractogram'][max_index]['2th_cuka'].max() + xminmax['2th_cuka'][2], xminmax['2th_cuka'][3] = xminmax['2th_cuka'][0], xminmax['2th_cuka'][1] + + xminmax['2th_moka'][0], xminmax['2th_moka'][1] = data['diffractogram'][min_index]['2th_moka'].min(), data['diffractogram'][max_index]['2th_moka'].max() + xminmax['2th_moka'][2], xminmax['2th_moka'][3] = xminmax['2th_moka'][0], xminmax['2th_moka'][1] + + xminmax['d'][0], xminmax['d'][1] = data['diffractogram'][max_index]['d'].min(), data['diffractogram'][min_index]['d'].max() # swapped, intended + xminmax['d'][2], xminmax['d'][3] = xminmax['d'][0], xminmax['d'][1] + + xminmax['1/d'][0], xminmax['1/d'][1] = data['diffractogram'][min_index]['1/d'].min(), data['diffractogram'][max_index]['1/d'].max() + xminmax['1/d'][2], xminmax['1/d'][3] = xminmax['1/d'][0], xminmax['1/d'][1] + + xminmax['q'][0], xminmax['q'][1] = data['diffractogram'][min_index]['q'].min(), data['diffractogram'][max_index]['q'].max() + xminmax['q'][2], xminmax['q'][3] = xminmax['q'][0], xminmax['q'][1] + + xminmax['q2'][0], xminmax['q2'][1] = data['diffractogram'][min_index]['q2'].min(), data['diffractogram'][max_index]['q2'].max() + xminmax['q2'][2], xminmax['q2'][3] = xminmax['q2'][0], xminmax['q2'][1] + + xminmax['q4'][0], xminmax['q4'][1] = data['diffractogram'][min_index]['q4'].min(), data['diffractogram'][max_index]['q4'].max() + xminmax['q4'][2], xminmax['q4'][3] = xminmax['q4'][0], xminmax['q4'][1] + + + xminmax['heatmap'] = options['heatmap_xlim'] # This value is set in the generate_heatmap()-function xminmax['start'][0], xminmax['start'][1] = xminmax[options['x_vals']][0], xminmax[options['x_vals']][1] - xminmax['start'][2], xminmax['start'][3] = xminmax[options['x_vals']][0], xminmax[options['x_vals']][1] + xminmax['start'][2], xminmax['start'][3] = xminmax[options['x_vals']][2], xminmax[options['x_vals']][3] -def update_yminmax(yminmax: dict, data, options={}): +def update_yminmax(yminmax: dict, data: dict, options={}) -> None: - for index, diffractogram in enumerate(data['diffractogram']): + yminmax['diff'] = [None, None, None, None] + # Go through diffractograms and find the minimum and maximum intensity values + for diffractogram in data['diffractogram']: if not yminmax['diff'][0] or (yminmax['diff'][0] > (diffractogram['I'].min())): yminmax['diff'][0] = diffractogram['I'].min() @@ -399,8 +431,9 @@ def update_yminmax(yminmax: dict, data, options={}): yminmax['diff'][1] = yminmax['diff'][1]*5 - yminmax['heatmap'][0] = 0 - yminmax['heatmap'][1] = data['heatmap'].shape[0] + # Set start values to the edges of the dataset + yminmax['heatmap'][0], yminmax['heatmap'][1] = 0, data['heatmap'].shape[0] + yminmax['heatmap'][2], yminmax['heatmap'][3] = yminmax['heatmap'][0], yminmax['heatmap'][1] if options['heatmap']: @@ -413,59 +446,89 @@ def update_yminmax(yminmax: dict, data, options={}): yminmax['start'][2], yminmax['start'][3] = yminmax['diff'][2], yminmax['diff'][3] +def update_defaults(widget: dict, minmax: dict) -> None: + ''' Updates the default x- or y-limits of a given widget. Refer to plot_diffractogram_interactive() to see the form of the widget that is passed in. An update of the min/max-values is done just prior to calling this function. + Changes dictionaries in place. + + Input: + widget (dict): A dictionary containing the widget itself (widget['w']) and all its default-values (e.g. widget['2th_default']) + minmax (dict): A dictionary containing min and max values, as well as min_start and max_start values. (e.g. minmax['2th'] is a list with four elements: [xmin, xmax, xmin_start, xmax_start]) + + Output: + None.''' + + for name, attr in widget.items(): + if name.endswith('default'): + attr['min'] = minmax[name.replace('_default', '')][0] + attr['max'] = minmax[name.replace('_default', '')][1] + attr['value'] = [minmax[name.replace('_default', '')][2], minmax[name.replace('_default', '')][3]] -def update_widgets(options): +def update_widgets(data, options): - for widget, attr in options['widgets'].items(): - if widget == 'xlim': + for widget_name, widget in options['widgets'].items(): - if options['heatmap'] and (attr['state'] != 'heatmap'): - setattr(attr['w'], 'min', attr['heatmap_default']['min']) - setattr(attr['w'], 'max', attr['heatmap_default']['max']) - setattr(attr['w'], 'value', attr['heatmap_default']['value']) - setattr(attr['w'], 'step', attr['heatmap_default']['step']) + # Make changes to xlim-widget + if widget_name == 'xlim': + # First update the min and max values + update_xminmax(xminmax=options['xminmax'], data=data, options=options) + update_defaults(widget=widget, minmax=options['xminmax']) + - attr['state'] = 'heatmap' + if options['heatmap'] and (widget['state'] != 'heatmap'): + + + setattr(widget['w'], 'min', widget['heatmap_default']['min']) + setattr(widget['w'], 'max', widget['heatmap_default']['max']) + setattr(widget['w'], 'value', widget['heatmap_default']['value']) + setattr(widget['w'], 'step', widget['heatmap_default']['step']) + + widget['state'] = 'heatmap' - elif not options['heatmap'] and (attr['state'] != options['x_vals']): - for arg in attr[f'{options["x_vals"]}_default']: + elif not options['heatmap'] and (widget['state'] != options['x_vals']): + # Then loop through all attributes in the widget and change to current mode. + for arg in widget[f'{options["x_vals"]}_default']: # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first if arg == 'min': - if attr[f'{options["x_vals"]}_default']['min'] > getattr(attr['w'], 'max'): - setattr(attr['w'], 'max', attr[f'{options["x_vals"]}_default']['max']) + if widget[f'{options["x_vals"]}_default']['min'] > getattr(widget['w'], 'max'): + setattr(widget['w'], 'max', widget[f'{options["x_vals"]}_default']['max']) elif arg == 'max': - if attr[f'{options["x_vals"]}_default']['max'] < getattr(attr['w'], 'min'): - setattr(attr['w'], 'min', attr[f'{options["x_vals"]}_default']['min']) + if widget[f'{options["x_vals"]}_default']['max'] < getattr(widget['w'], 'min'): + setattr(widget['w'], 'min', widget[f'{options["x_vals"]}_default']['min']) - setattr(attr['w'], arg, attr[f'{options["x_vals"]}_default'][arg]) + setattr(widget['w'], arg, widget[f'{options["x_vals"]}_default'][arg]) - attr['state'] = options['x_vals'] + widget['state'] = options['x_vals'] - elif widget == 'ylim': - state = 'heatmap' if options['heatmap'] else 'diff' + # Make changes to ylim-widget + elif widget_name == 'ylim': + update_yminmax(yminmax=options['yminmax'], data=data, options=options) + update_defaults(widget=widget, minmax=options['yminmax']) + + state = 'heatmap' if options['heatmap'] else 'diff' - if attr['state'] != state: + if widget['state'] != state or options['offset_change']: - for arg in attr[f'{state}_default']: + for arg in widget[f'{state}_default']: # If new min value is larger than previous max, or new max value is smaller than previous min, set the opposite first if arg == 'min': - if attr[f'{state}_default']['min'] > getattr(attr['w'], 'max'): - setattr(attr['w'], 'max', attr[f'{state}_default']['max']) + if widget[f'{state}_default']['min'] > getattr(widget['w'], 'max'): + setattr(widget['w'], 'max', widget[f'{state}_default']['max']) elif arg == 'max': - if attr[f'{state}_default']['max'] < getattr(attr['w'], 'min'): - setattr(attr['w'], 'min', attr[f'{state}_default']['min']) + if widget[f'{state}_default']['max'] < getattr(widget['w'], 'min'): + setattr(widget['w'], 'min', widget[f'{state}_default']['min']) - setattr(attr['w'], arg, attr[f'{state}_default'][arg]) - - attr['state'] = state + setattr(widget['w'], arg, widget[f'{state}_default'][arg]) + + options['offset_change'] = False + widget['state'] = state From dd7f2d9dea4f91ea3758ab776d0ef5c01037fce3 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Wed, 6 Apr 2022 12:44:33 +0200 Subject: [PATCH 8/9] Fix bug making last commit not work as intended --- beamtime/xrd/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index 9012b4a..db60b1a 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -54,7 +54,7 @@ def plot_diffractogram(data, options={}): default_options['offset_y'] = 0.05 options = aux.update_options(options=options, required_options=required_options, default_options=default_options) - options['current_offset_y'] = options['offset_y'] + #options['current_offset_y'] = options['offset_y'] # Convert data['path'] to list to allow iteration over this to accommodate both single and multiple diffractograms if not isinstance(data['path'], list): From 63726033249475c45a897d45fb311f08feb7ce99 Mon Sep 17 00:00:00 2001 From: rasmusvt Date: Wed, 6 Apr 2022 13:42:34 +0200 Subject: [PATCH 9/9] Translate relfections to heatmap x-coords --- beamtime/xrd/io.py | 25 ++++++++++++++++---- beamtime/xrd/plot.py | 54 ++++++++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/beamtime/xrd/io.py b/beamtime/xrd/io.py index 910811b..c2447d8 100644 --- a/beamtime/xrd/io.py +++ b/beamtime/xrd/io.py @@ -400,7 +400,7 @@ def revert_offset(diffractogram,which=None): return diffractogram -def load_reflection_table(data, options={}): +def load_reflection_table(data: dict, reflections_params: dict, options={}): required_options = ['ref_wavelength', 'to_wavelength'] @@ -413,12 +413,12 @@ def load_reflection_table(data, options={}): # VESTA outputs the file with a header that has a space between the parameter and units - so there is some extra code to rectify the issue # that ensues from this formatting - reflections = pd.read_csv(data['path'], delim_whitespace=True) + reflections = pd.read_csv(reflections_params['path'], delim_whitespace=True) # Remove the extra column that appears from the headers issue reflections.drop(reflections.columns[-1], axis=1, inplace=True) - with open(data['path'], 'r') as f: + with open(reflections_params['path'], 'r') as f: line = f.readline() headers = line.split() @@ -434,13 +434,28 @@ def load_reflection_table(data, options={}): reflections = translate_wavelengths(data=reflections, wavelength=options['ref_wavelength'], to_wavelength=options['to_wavelength']) - #print(reflections) + if 'heatmap' in data.keys(): + + start_2th, stop_2th = data['diffractogram'][0]['2th'].min(), data['diffractogram'][0]['2th'].max() + len_2th = stop_2th - start_2th + #print(start_2th, stop_2th, len_2th) + + start_heatmap, stop_heatmap = 0, data['heatmap'].shape[1] + len_heatmap = stop_heatmap - start_heatmap + #print(start_heatmap, stop_heatmap, len_heatmap) + + scale = len_heatmap/len_2th + + #print(scale) + #print(stop_2th * scale) + + reflections['heatmap'] = (reflections['2th']-start_2th) * scale return reflections -def translate_wavelengths(data, wavelength, to_wavelength=None): +def translate_wavelengths(data: pd.DataFrame, wavelength: float, to_wavelength=None) -> pd.DataFrame: # FIXME Somewhere here there is an invalid arcsin-argument. Not sure where. pd.options.mode.chained_assignment = None diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index db60b1a..cc6baa3 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -80,6 +80,8 @@ def plot_diffractogram(data, options={}): # Generate heatmap data data['heatmap'], data['heatmap_xticks'], data['heatmap_xticklabels'] = generate_heatmap(data=data, options=options) + options['heatmap_loaded'] = True + if options['heatmap']: options['xlim'] = options['heatmap_xlim'] @@ -163,16 +165,16 @@ def plot_diffractogram(data, options={}): options['xlim'] = ax.get_xlim() options['to_wavelength'] = data['wavelength'][0] - for reference, axis in zip(options['reflections_data'], ref_axes): - plot_reflection_table(data=reference, ax=axis, options=options) + for reflections_params, axis in zip(options['reflections_data'], ref_axes): + plot_reflection_table(data=data, reflections_params=reflections_params, ax=axis, options=options) # Print the reflection indices. By default, the wavelength of the first diffractogram will be used for this. if options['reflections_indices'] and options['reflections_data']: options['xlim'] = ax.get_xlim() options['to_wavelength'] = data['wavelength'][0] - for reference in options['reflections_data']: - plot_reflection_indices(data=reference, ax=indices_ax, options=options) + for reflections_params in options['reflections_data']: + plot_reflection_indices(data=data, reflections_params=reflections_params, ax=indices_ax, options=options) if options['interactive_session_active']: @@ -533,7 +535,7 @@ def update_widgets(data, options): -def plot_reflection_indices(data, ax, options={}): +def plot_reflection_indices(data, reflections_params, ax, options={}): ''' Print reflection indices from output generated by VESTA. Required contents of data: @@ -547,20 +549,21 @@ def plot_reflection_indices(data, ax, options={}): 'hide_indices': False } - data = aux.update_options(options=data, required_options=required_options, default_options=default_options) + reflections_params = aux.update_options(options=reflections_params, required_options=required_options, default_options=default_options) - if not data['hide_indices']: - reflection_table = xrd.io.load_reflection_table(data=data, options=options) + if not reflections_params['hide_indices']: + reflection_table = xrd.io.load_reflection_table(data=data, reflections_params=reflections_params, options=options) - if data['reflection_indices'] > 0: + if reflections_params['reflection_indices'] > 0: # Get the data['reflection_indices'] number of highest reflections within the subrange options['xlim'] - reflection_indices = reflection_table.loc[(reflection_table[options['x_vals']] > options['xlim'][0]) & (reflection_table[options['x_vals']] < options['xlim'][1])].nlargest(options['reflection_indices'], 'I') + x_vals = 'heatmap' if options['heatmap'] else options['x_vals'] + reflection_indices = reflection_table.loc[(reflection_table[x_vals] > options['xlim'][0]) & (reflection_table[x_vals] < options['xlim'][1])].nlargest(options['reflection_indices'], 'I') # Plot the indices - for i in range(data['reflection_indices']): + for i in range(reflections_params['reflection_indices']): if reflection_indices.shape[0] > i: - ax.text(s=f'({reflection_indices["h"].iloc[i]} {reflection_indices["k"].iloc[i]} {reflection_indices["l"].iloc[i]})', x=reflection_indices[options['x_vals']].iloc[i], y=0, fontsize=2.5, rotation=90, va='bottom', ha='center', c=data['text_colour']) + ax.text(s=f'({reflection_indices["h"].iloc[i]} {reflection_indices["k"].iloc[i]} {reflection_indices["l"].iloc[i]})', x=reflection_indices[x_vals].iloc[i], y=0, fontsize=2.5, rotation=90, va='bottom', ha='center', c=reflections_params['text_colour']) if options['xlim']: @@ -571,7 +574,7 @@ def plot_reflection_indices(data, ax, options={}): return -def plot_reflection_table(data, ax=None, options={}): +def plot_reflection_table(data, reflections_params, ax=None, options={}): ''' Plots a reflection table from output generated by VESTA. Required contents of data: @@ -590,15 +593,15 @@ def plot_reflection_table(data, ax=None, options={}): } if 'colour' in data.keys(): - options['reflections_colour'] = data['colour'] - if 'min_alpha' in data.keys(): - options['min_alpha'] = data['min_alpha'] - if 'reflection_indices' in data.keys(): - options['reflection_indices'] = data['reflection_indices'] - if 'label' in data.keys(): - options['label'] = data['label'] - if 'wavelength' in data.keys(): - options['wavelength'] = data['wavelength'] + options['reflections_colour'] = reflections_params['colour'] + if 'min_alpha' in reflections_params.keys(): + options['min_alpha'] = reflections_params['min_alpha'] + if 'reflection_indices' in reflections_params.keys(): + options['reflection_indices'] = reflections_params['reflection_indices'] + if 'label' in reflections_params.keys(): + options['label'] = reflections_params['label'] + if 'wavelength' in reflections_params.keys(): + options['wavelength'] = reflections_params['wavelength'] options = aux.update_options(options=options, required_options=required_options, default_options=default_options) @@ -606,9 +609,10 @@ def plot_reflection_table(data, ax=None, options={}): if not ax: _, ax = btp.prepare_plot(options) - reflection_table = xrd.io.load_reflection_table(data=data, options=options) + x_vals = 'heatmap' if options['heatmap'] else options['x_vals'] - reflections, intensities = reflection_table[options['x_vals']], reflection_table['I'] + reflection_table = xrd.io.load_reflection_table(data=data, reflections_params=reflections_params, options=options) + reflections, intensities = reflection_table[x_vals], reflection_table['I'] @@ -638,7 +642,7 @@ def plot_reflection_table(data, ax=None, options={}): xlim_range = ax.get_xlim()[1] - ax.get_xlim()[0] ylim_avg = (ax.get_ylim()[0]+ax.get_ylim()[1])/2 - ax.text(s=data['label'], x=(ax.get_xlim()[0]-0.01*xlim_range), y=ylim_avg, ha = 'right', va = 'center') + ax.text(s=reflections_params['label'], x=(ax.get_xlim()[0]-0.01*xlim_range), y=ylim_avg, ha = 'right', va = 'center')