Add reflection table and interactive mode to xrd

This commit is contained in:
rasmusvt 2022-03-12 22:26:06 +01:00
parent 67ea048380
commit a5c845fa54
3 changed files with 213 additions and 19 deletions

View file

@ -25,7 +25,9 @@ def prepare_plot(options={}):
rc_params = options['rc_params'] rc_params = options['rc_params']
format_params = options['format_params'] format_params = options['format_params']
required_format_params = ['single_column_width', 'double_column_width', 'column_type', 'width_ratio', 'aspect_ratio', 'compress_width', 'compress_height', 'upscaling_factor', 'dpi'] required_format_params = ['single_column_width', 'double_column_width', 'column_type', 'width_ratio', 'aspect_ratio',
'width', 'height', 'compress_width', 'compress_height', 'upscaling_factor', 'dpi',
'nrows', 'ncols', 'grid_ratio_height', 'grid_ratio_width']
default_format_params = { default_format_params = {
'single_column_width': 8.3, 'single_column_width': 8.3,
@ -33,10 +35,16 @@ def prepare_plot(options={}):
'column_type': 'single', 'column_type': 'single',
'width_ratio': '1:1', 'width_ratio': '1:1',
'aspect_ratio': '1:1', 'aspect_ratio': '1:1',
'width': None,
'height': None,
'compress_width': 1, 'compress_width': 1,
'compress_height': 1, 'compress_height': 1,
'upscaling_factor': 1.0, 'upscaling_factor': 1.0,
'dpi': 600, 'dpi': 600,
'nrows': 1,
'ncols': 1,
'grid_ratio_height': None,
'grid_ratio_width': None
} }
format_params = aux.update_options(format_params, required_format_params, default_format_params) format_params = aux.update_options(format_params, required_format_params, default_format_params)
@ -48,13 +56,72 @@ def prepare_plot(options={}):
# Update run commands if any is passed (will pass an empty dictionary if not passed) # Update run commands if any is passed (will pass an empty dictionary if not passed)
update_rc_params(rc_params) update_rc_params(rc_params)
width = determine_width(format_params=format_params) if not format_params['width']:
height = determine_height(format_params=format_params, width=width) width = determine_width(format_params=format_params)
if not format_params['height']:
height = determine_height(format_params=format_params, width=width)
width, height = scale_figure(format_params=format_params, width=width, height=height) width, height = scale_figure(format_params=format_params, width=width, height=height)
fig, ax = plt.subplots(figsize=(width, height), dpi=format_params['dpi']) if format_params['nrows'] == 1 and format_params['ncols'] == 1:
fig, ax = plt.subplots(figsize=(width, height), dpi=format_params['dpi'])
return fig, ax return fig, ax
else:
if not format_params['grid_ratio_height']:
format_params['grid_ratio_height'] = [1 for i in range(format_params['nrows'])]
if not format_params['grid_ratio_width']:
format_params['grid-ratio_width'] = [1 for i in range(format_params['ncols'])]
fig, axes = plt.subplots(nrows=format_params['nrows'], ncols=format_params['ncols'], figsize=(width,height),
gridspec_kw={'height_ratios': format_params['grid_ratio_height'], 'width_ratios': format_params['grid_ratio_width']},
facecolor='w', dpi=format_params['dpi'])
return fig, axes
def prepare_plots(options={}):
rc_params = options['rc_params']
format_params = options['format_params']
required_options = ['single_column_width', 'double_column_width', 'column_type', 'width_ratio', 'aspect_ratio', 'compress_width', 'compress_height', 'upscaling_factor', 'dpi']
default_options = {
'single_column_width': 8.3,
'double_column_width': 17.1,
'column_type': 'single',
'width_ratio': '1:1',
'aspect_ratio': '1:1',
'compress_width': 1,
'compress_height': 1,
'upscaling_factor': 1.0,
'dpi': 600,
}
format_params = aux.update_options(format_params, required_options, default_options)
# Reset run commands
plt.rcdefaults()
# Update run commands if any is passed (will pass an empty dictionary if not passed)
update_rc_params(rc_params)
width = determine_width(format_params)
height = determine_height(format_params, width)
width, height = scale_figure(options=format_params, width=width, height=height)
if options['plot_kind'] == 'relative':
fig, axes = plt.subplots(nrows=1, ncols=options['number_of_frames'], figsize=(width,height), facecolor='w', dpi=format_params['dpi'])
elif options['plot_kind'] == 'absolute':
fig, axes = plt.subplots(nrows=2, ncols=options['number_of_frames'], figsize=(width,height), gridspec_kw={'height_ratios': [1,5]}, facecolor='w', dpi=format_params['dpi'])
return fig, axes
def adjust_plot(fig, ax, options): def adjust_plot(fig, ax, options):

View file

@ -87,7 +87,7 @@ def integrate_1d(calibrant, bins, path=None, image=None, options=None):
res = ai.integrate1d(image, bins, unit=options['unit'], filename=filename) res = ai.integrate1d(image, bins, unit=options['unit'], filename=filename)
if options['return']: if options['return']:
return open_1d_data(filename) return read_diffractogram(filename)
@ -222,7 +222,7 @@ def read_brml(path, options=None):
return diffractogram return diffractogram
def read_diffractogram(path, options=None): def read_diffractogram(path):
@ -248,7 +248,7 @@ def read_diffractogram(path, options=None):
def read_data(path, kind, options=None): def read_data(path, kind, options=None):
if kind == 'beamline': if kind == 'beamline':
diffractogram = read_diffractogram(path, options=options) diffractogram = read_diffractogram(path)
elif kind == 'recx': elif kind == 'recx':
diffractogram = read_brml(path, options=options) diffractogram = read_brml(path, options=options)

View file

@ -5,8 +5,9 @@ import pandas as pd
import numpy as np import numpy as np
import math import math
import beamtime.xrd as xrd import ipywidgets as widgets
import beamtime.xrd as xrd
import beamtime.auxillary as aux import beamtime.auxillary as aux
import beamtime.plotting as btp import beamtime.plotting as btp
@ -18,42 +19,168 @@ def plot_diffractogram(plot_data, options={}):
plot_data (dict): Must include path = string to diffractogram data, and plot_kind = (recx, beamline, image)''' plot_data (dict): Must include path = string to diffractogram data, and plot_kind = (recx, beamline, image)'''
# Update options # Update options
required_options = ['x_vals', 'y_vals', 'ylabel', 'xlabel', 'xunit', 'yunit', 'scatter', 'plot_kind', 'rc_params', 'format_params'] required_options = ['x_vals', 'y_vals', 'ylabel', 'xlabel', 'xunit', 'yunit', 'line', 'scatter',
'reflections', 'plot_kind', 'palettes', 'interactive', 'rc_params', 'format_params']
default_options = { default_options = {
'x_vals': '2th', 'x_vals': '2th',
'y_vals': 'I', 'y_vals': 'I',
'ylabel': 'Intensity', 'xlabel': '2theta', 'ylabel': 'Intensity', 'xlabel': '2theta',
'xunit': 'deg', 'yunit': 'a.u.', 'xunit': 'deg', 'yunit': 'a.u.',
'line': True,
'scatter': False, 'scatter': False,
'reflections': False,
'reflection_data': None, # Should be passed as a dictionary on the form {path: rel_path, colour: [r,g,b], min_alpha: 0-1]
'plot_kind': None, 'plot_kind': None,
'palettes': [('qualitative', 'Dark2_8')],
'interactive': False,
'rc_params': {}, 'rc_params': {},
'format_params': {} 'format_params': {},
} }
options = aux.update_options(options=options, required_options=required_options, default_options=default_options) options = aux.update_options(options=options, required_options=required_options, default_options=default_options)
# Prepare plot, and read and process data if options['interactive']:
fig, ax = btp.prepare_plot(options=options) options['interactive'] = False
diffractogram = xrd.io.read_data(path=plot_data['path'], kind=plot_data['plot_kind'], options=options) plot_diffractogram_interactive(plot_data=plot_data, options=options)
return
if options['scatter']: # Make adjustments to parameters if reflections data is passed
ax.scatter(x= diffractogram[options['x_vals']], y = diffractogram[options['y_vals']]) if options['reflections']:
options['format_params']['nrows'] = 2
#diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax, kind='scatter') if not 'grid_ratio_height' in options['format_params'].keys():
options['format_params']['grid_ratio_height'] = [1,10]
else: else:
diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax) options['format_params']['nrows'] = 1
# Prepare plot, and read and process data
fig, ax = btp.prepare_plot(options=options)
if options['reflections']:
reflection_ax = ax[0]
ax = ax[1]
colours = btp.generate_colours(options['palettes'])
diffractogram = xrd.io.read_data(path=plot_data['path'], kind=plot_data['plot_kind'], options=options)
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)]))
fig, ax = btp.adjust_plot(fig=fig, ax=ax, options=options) fig, ax = btp.adjust_plot(fig=fig, ax=ax, options=options)
if options['reflections'] and options['reflection_data']:
plot_reflection_table(plot_data=options['reflection_data'], ax=reflection_ax, options=options)
return diffractogram, fig, ax return diffractogram, fig, ax
def plot_diffractogram_interactive(plot_data, options):
if options['reflections']:
w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_diffractogram), plot_data=widgets.fixed(plot_data), options=widgets.fixed(options),
scatter=widgets.ToggleButton(value=False),
line=widgets.ToggleButton(value=True),
reflections=widgets.ToggleButton(value=True))
else:
w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_diffractogram), plot_data=widgets.fixed(plot_data), options=widgets.fixed(options),
scatter=widgets.ToggleButton(value=False),
line=widgets.ToggleButton(value=True))
display(w)
def plot_reflection_table(plot_data, ax=None, options={}):
''' Plots a reflection table from output generated by VESTA.
Required contents of plot_data:
path (str): relative path to reflection table file'''
required_options = ['reflections_colour', 'min_alpha', 'format_params', 'rc_params']
default_options = {
'reflections_colour': [0,0,0],
'min_alpha': 0,
'format_params': {},
'rc_params': {}
}
if 'colour' in plot_data.keys():
options['reflections_colour'] = plot_data['colour']
if 'min_alpha' in plot_data.keys():
options['min_alpha'] = plot_data['min_alpha']
options = aux.update_options(options=options, required_options=required_options, default_options=default_options)
if not ax:
_, ax = btp.prepare_plot(options)
reflection_table = load_reflection_table(plot_data['path'])
reflections, intensities = reflection_table['2th'], reflection_table['I']
for ref, intensity in zip(reflections, intensities):
rel_intensity = (intensity / intensities.max())*(1-options['min_alpha']) + options['min_alpha']
ax.axvline(x=ref, c=options['reflections_colour'], alpha=rel_intensity)
ax.tick_params(which='both', bottom=False, labelbottom=False, right=False, labelright=False, left=False, labelleft=False, top=False, labeltop=False)
if options['xlim']:
ax.set_xlim(options['xlim'])
def load_reflection_table(path):
# 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(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(path, 'r') as f:
line = f.readline()
headers = line.split()
# Delete the fourth element which is '(Å)'
del headers[4]
# Change name of column to avoid using greek letters
headers[7] = '2th'
# Set the new modified headers as the headers of
reflections.columns = headers
return reflections
def prepare_diffractogram_plot(options=None): def prepare_diffractogram_plot(options=None):
# First take care of the options for plotting - set any values not specified to the default values # First take care of the options for plotting - set any values not specified to the default values