Merge pull request #4 from rasmusthog/rasmus_small_improvements

Rasmus small improvements
This commit is contained in:
Rasmus Vester Thøgersen 2022-05-19 19:33:02 +00:00 committed by GitHub
commit 9490c338c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 51 deletions

View file

@ -178,19 +178,17 @@ def process_batsmall_data(df, options=None):
def splice_cycles(df, options: dict) -> pd.DataFrame: def splice_cycles(df, options: dict) -> pd.DataFrame:
''' Splices two cycles together - if e.g. one charge cycle are split into several cycles due to change in parameters. ''' Splices two cycles together - if e.g. one charge cycle are split into several cycles due to change in parameters.
Incomplete, only accomodates BatSmall so far.''' Incomplete, only accomodates BatSmall so far, and only for charge.'''
if options['kind'] == 'batsmall': if options['kind'] == 'batsmall':
# Creates masks for charge and discharge curves # Creates masks for charge and discharge curves
chg_mask = df['current'] >= 0 chg_mask = df['current'] >= 0
dchg_mask = df['current'] < 0
# Loop through all the cycling steps, change the current and capacities in the # Loop through all the cycling steps, change the current and capacities in the
for i in range(df["count"].max()): for i in range(df["count"].max()):
sub_df = df.loc[df['count'] == i+1] sub_df = df.loc[df['count'] == i+1]
sub_df_chg = sub_df.loc[chg_mask] sub_df_chg = sub_df.loc[chg_mask]
#sub_df_dchg = sub_df.loc[dchg_mask]
# get indices where the program changed # get indices where the program changed
chg_indices = sub_df_chg[sub_df_chg["comment"].str.contains("program")==True].index.to_list() chg_indices = sub_df_chg[sub_df_chg["comment"].str.contains("program")==True].index.to_list()
@ -202,34 +200,17 @@ def splice_cycles(df, options: dict) -> pd.DataFrame:
if chg_indices: if chg_indices:
last_chg = chg_indices.pop() last_chg = chg_indices.pop()
#dchg_indices = sub_df_dchg[sub_df_dchg["comment"].str.contains("program")==True].index.to_list()
#if dchg_indices:
# del dchg_indices[0]
if chg_indices: if chg_indices:
for i in chg_indices: for i in chg_indices:
add = df['specific_capacity'].iloc[i-1] add = df['specific_capacity'].iloc[i-1]
df['specific_capacity'].iloc[i:last_chg] = df['specific_capacity'].iloc[i:last_chg] + add df['specific_capacity'].iloc[i:last_chg] = df['specific_capacity'].iloc[i:last_chg] + add
#if dchg_indices:
# for i in dchg_indices:
# add = df['specific_capacity'].iloc[i-1]
# df['specific_capacity'].iloc[i:last_dchg] = df['specific_capacity'].iloc[i:last_dchg] + add
return df return df
def process_neware_data(df, options={}): def process_neware_data(df, options={}):
""" Takes data from NEWARE in a DataFrame as read by read_neware() and converts units, adds columns and splits into cycles. """ Takes data from NEWARE in a DataFrame as read by read_neware() and converts units, adds columns and splits into cycles.

View file

@ -5,40 +5,55 @@ import pandas as pd
import numpy as np import numpy as np
import math import math
import ipywidgets as widgets
from IPython.display import display
import nafuma.electrochemistry as ec import nafuma.electrochemistry as ec
import nafuma.plotting as btp import nafuma.plotting as btp
import nafuma.auxillary as aux import nafuma.auxillary as aux
def plot_gc(data, options=None): def plot_gc(data, options=None):
# Update options # Update options
required_options = ['x_vals', 'y_vals', 'which_cycles', 'charge', 'discharge', 'colours', 'differentiate_charge_discharge', 'gradient', 'rc_params', 'format_params'] required_options = ['x_vals', 'y_vals', 'which_cycles', 'charge', 'discharge', 'colours', 'differentiate_charge_discharge', 'gradient', 'interactive', 'interactive_session_active', 'rc_params', 'format_params']
default_options = { default_options = {
'x_vals': 'capacity', 'y_vals': 'voltage', 'x_vals': 'capacity', 'y_vals': 'voltage',
'which_cycles': 'all', 'which_cycles': 'all',
'charge': True, 'discharge': True, 'charge': True, 'discharge': True,
'colours': None, 'colours': None,
'differentiate_charge_discharge': True, 'differentiate_charge_discharge': True,
'gradient': False, 'gradient': False,
'interactive': False,
'interactive_session_active': 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
fig, ax = btp.prepare_plot(options=options) if not 'cycles' in data.keys():
data['cycles'] = ec.io.read_data(data=data, options=options) data['cycles'] = ec.io.read_data(data=data, options=options)
# Update list of cycles to correct indices # Update list of cycles to correct indices
update_cycles_list(cycles=data['cycles'], options=options) update_cycles_list(cycles=data['cycles'], options=options)
colours = generate_colours(cycles=data['cycles'], options=options) colours = generate_colours(cycles=data['cycles'], options=options)
if options['interactive']:
options['interactive'], options['interactive_session_active'] = False, True
plot_gc_interactive(data=data, options=options)
return
# Prepare plot, and read and process data
fig, ax = btp.prepare_plot(options=options)
for i, cycle in enumerate(data['cycles']): for i, cycle in enumerate(data['cycles']):
if i in options['which_cycles']: if i in options['which_cycles']:
@ -49,25 +64,42 @@ def plot_gc(data, options=None):
cycle[1].plot(x=options['x_vals'], y=options['y_vals'], ax=ax, c=colours[i][1]) cycle[1].plot(x=options['x_vals'], y=options['y_vals'], ax=ax, c=colours[i][1])
update_labels(options) if options['interactive_session_active']:
print(options['xunit']) update_labels(options, force=True)
else:
update_labels(options)
fig, ax = btp.adjust_plot(fig=fig, ax=ax, options=options) fig, ax = btp.adjust_plot(fig=fig, ax=ax, options=options)
return data['cycles'], fig, ax #if options['interactive_session_active']:
return data['cycles'], fig, ax
def plot_gc_interactive(data, options):
def update_labels(options): w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_gc), data=widgets.fixed(data), options=widgets.fixed(options),
charge=widgets.ToggleButton(value=True),
discharge=widgets.ToggleButton(value=True),
x_vals=widgets.Dropdown(options=['specific_capacity', 'capacity', 'ions', 'voltage', 'time', 'energy'], value='specific_capacity', description='X-values')
)
if 'xlabel' not in options.keys(): options['widget'] = w
display(w)
def update_labels(options, force=False):
if 'xlabel' not in options.keys() or force:
options['xlabel'] = options['x_vals'].capitalize().replace('_', ' ') options['xlabel'] = options['x_vals'].capitalize().replace('_', ' ')
if 'ylabel' not in options.keys(): if 'ylabel' not in options.keys() or force:
options['ylabel'] = options['y_vals'].capitalize().replace('_', ' ') options['ylabel'] = options['y_vals'].capitalize().replace('_', ' ')
if 'xunit' not in options.keys(): if 'xunit' not in options.keys() or force:
if options['x_vals'] == 'capacity': if options['x_vals'] == 'capacity':
options['xunit'] = options['units']['capacity'] options['xunit'] = options['units']['capacity']
elif options['x_vals'] == 'specific_capacity': elif options['x_vals'] == 'specific_capacity':
@ -78,7 +110,7 @@ def update_labels(options):
options['xunit'] = None options['xunit'] = None
if 'yunit' not in options.keys(): if 'yunit' not in options.keys() or force:
if options['y_vals'] == 'voltage': if options['y_vals'] == 'voltage':
options['yunit'] = options['units']['voltage'] options['yunit'] = options['units']['voltage']

View file

@ -59,9 +59,10 @@ def integrate_1d(data, options={}, index=0):
# Get image array from filename if not passed # Get image array from filename if not passed
if 'image' not in data.keys(): if 'image' not in data.keys() or not data['image']:
data['image'] = get_image_array(data['path'][index]) data['image'] = get_image_array(data['path'][index])
# Instanciate the azimuthal integrator from pyFAI from the calibrant (.poni-file) # Instanciate the azimuthal integrator from pyFAI from the calibrant (.poni-file)
ai = pyFAI.load(data['calibrant']) ai = pyFAI.load(data['calibrant'])
@ -72,11 +73,15 @@ def integrate_1d(data, options={}, index=0):
if not os.path.isdir(options['extract_folder']): if not os.path.isdir(options['extract_folder']):
os.makedirs(options['extract_folder']) os.makedirs(options['extract_folder'])
if not os.path.isdir(options['save_folder']):
os.makedirs(options['save_folder'])
res = ai.integrate1d(data['image'], options['nbins'], unit=options['unit'], filename=filename) res = ai.integrate1d(data['image'], options['nbins'], unit=options['unit'], filename=filename)
data['path'][index] = filename data['path'][index] = filename
diffractogram, wavelength = read_xy(data=data, options=options, index=index) diffractogram, _ = read_xy(data=data, options=options, index=index)
wavelength = find_wavelength_from_poni(path=data['calibrant'])
if not options['save']: if not options['save']:
os.remove(filename) os.remove(filename)
@ -278,8 +283,12 @@ def read_brml(data, options={}, index=0):
#if 'wavelength' not in data.keys(): #if 'wavelength' not in data.keys():
# Find wavelength # Find wavelength
for chain in root.findall('./FixedInformation/Instrument/PrimaryTracks/TrackInfoData/MountedOptics/InfoData/Tube/WaveLengthAlpha1'):
wavelength = float(chain.attrib['Value']) if not data['wavelength'][index]:
for chain in root.findall('./FixedInformation/Instrument/PrimaryTracks/TrackInfoData/MountedOptics/InfoData/Tube/WaveLengthAlpha1'):
wavelength = float(chain.attrib['Value'])
else:
wavelength = data['wavelength'][index]
diffractogram = pd.DataFrame(diffractogram) diffractogram = pd.DataFrame(diffractogram)
@ -302,7 +311,11 @@ def read_xy(data, options={}, index=0):
#if 'wavelength' not in data.keys(): #if 'wavelength' not in data.keys():
# Get wavelength from scan # Get wavelength from scan
wavelength = find_wavelength_from_xy(path=data['path'][index])
if not data['wavelength'][index]:
wavelength = find_wavelength_from_xy(path=data['path'][index])
else:
wavelength = data['wavelength'][index]
with open(data['path'][index], 'r') as f: with open(data['path'][index], 'r') as f:
position = 0 position = 0
@ -326,6 +339,38 @@ def read_xy(data, options={}, index=0):
return diffractogram, wavelength return diffractogram, wavelength
def strip_headers_from_xy(path: str, filename=None) -> None:
''' Strips headers from a .xy-file'''
xy = []
with open(path, 'r') as f:
lines = f.readlines()
headerlines = 0
for line in lines:
if line[0] == '#':
headerlines += 1
else:
xy.append(line)
if not filename:
ext = path.split('.')[-1]
filename = path.split(f'.{ext}')[0] + f'_noheaders.{ext}'
with open(filename, 'w') as f:
for line in xy:
f.write(line)
def read_data(data, options={}, index=0): def read_data(data, options={}, index=0):
beamline_extensions = ['mar3450', 'edf', 'cbf'] beamline_extensions = ['mar3450', 'edf', 'cbf']
@ -342,7 +387,7 @@ def read_data(data, options={}, index=0):
if options['offset'] or options['normalise']: if options['offset'] or options['normalise']:
# Make copy of the original intensities before any changes are made through normalisation or offset, to easily revert back if need to update. # Make copy of the original intensities before any changes are made through normalisation or offset, to easily revert back if need to update.
diffractogram['I_org'] = diffractogram['I'] diffractogram['I_org'] = diffractogram['I']
@ -351,6 +396,7 @@ def read_data(data, options={}, index=0):
diffractogram = apply_offset(diffractogram, wavelength, index, options) diffractogram = apply_offset(diffractogram, wavelength, index, options)
diffractogram = translate_wavelengths(data=diffractogram, wavelength=wavelength) diffractogram = translate_wavelengths(data=diffractogram, wavelength=wavelength)
return diffractogram, wavelength return diffractogram, wavelength
@ -470,7 +516,7 @@ def translate_wavelengths(data: pd.DataFrame, wavelength: float, to_wavelength=N
data['2th_cuka'] = np.NAN data['2th_cuka'] = np.NAN
data['2th_cuka'].loc[data['2th'] <= max_2th_cuka] = 2*np.arcsin(cuka/wavelength * np.sin((data['2th']/2) * np.pi/180)) * 180/np.pi data['2th_cuka'].loc[data['2th'] <= max_2th_cuka] = 2*np.arcsin(cuka/wavelength * np.sin((data['2th'].loc[data['2th'] <= max_2th_cuka]/2) * np.pi/180)) * 180/np.pi
# Translate to MoKalpha # Translate to MoKalpha
moka = 0.71073 # Å moka = 0.71073 # Å
@ -482,7 +528,7 @@ def translate_wavelengths(data: pd.DataFrame, wavelength: float, to_wavelength=N
data['2th_moka'] = np.NAN data['2th_moka'] = np.NAN
data['2th_moka'].loc[data['2th'] <= max_2th_moka] = 2*np.arcsin(moka/wavelength * np.sin((data['2th']/2) * np.pi/180)) * 180/np.pi data['2th_moka'].loc[data['2th'] <= max_2th_moka] = 2*np.arcsin(moka/wavelength * np.sin((data['2th'].loc[data['2th'] <= max_2th_moka]/2) * np.pi/180)) * 180/np.pi
# Convert to other parameters # Convert to other parameters
@ -501,7 +547,7 @@ def translate_wavelengths(data: pd.DataFrame, wavelength: float, to_wavelength=N
data['2th'] = np.NAN data['2th'] = np.NAN
data['2th'].loc[data['2th_cuka'] <= max_2th] = 2*np.arcsin(to_wavelength/cuka * np.sin((data['2th_cuka']/2) * np.pi/180)) * 180/np.pi data['2th'].loc[data['2th_cuka'] <= max_2th] = 2*np.arcsin(to_wavelength/cuka * np.sin((data['2th_cuka'].loc[data['2th_cuka'] <= max_2th]/2) * np.pi/180)) * 180/np.pi
@ -528,6 +574,22 @@ def find_wavelength_from_xy(path):
elif 'Wavelength' in line: elif 'Wavelength' in line:
wavelength = float(line.split()[2])*10**10 wavelength = float(line.split()[2])*10**10
else:
wavelength = None
return wavelength
def find_wavelength_from_poni(path):
with open(path, 'r') as f:
lines = f.readlines()
for line in lines:
if 'Wavelength' in line:
wavelength = float(line.split()[-1])*10**10
return wavelength return wavelength

View file

@ -13,7 +13,6 @@ import nafuma.xrd as xrd
import nafuma.auxillary as aux import nafuma.auxillary as aux
import nafuma.plotting as btp import nafuma.plotting as btp
def plot_diffractogram(data, options={}): def plot_diffractogram(data, options={}):
''' Plots a diffractogram. ''' Plots a diffractogram.
@ -67,7 +66,14 @@ def plot_diffractogram(data, options={}):
if not 'diffractogram' in data.keys(): if not 'diffractogram' in data.keys():
# Initialise empty list for diffractograms and wavelengths # Initialise empty list for diffractograms and wavelengths
data['diffractogram'] = [None for _ in range(len(data['path']))] data['diffractogram'] = [None for _ in range(len(data['path']))]
data['wavelength'] = [None for _ in range(len(data['path']))]
# If wavelength is not manually passed it should be automatically gathered from the .xy-file
if 'wavelength' not in data.keys():
data['wavelength'] = [None for _ in range(len(data['path']))]
else:
# If only a single value is passed it should be set to be the same for all diffractograms passed
if not isinstance(data['wavelength'], list):
data['wavelength'] = [data['wavelength'] for _ in range(len(data['path']))]
for index in range(len(data['path'])): for index in range(len(data['path'])):
diffractogram, wavelength = xrd.io.read_data(data=data, options=options, index=index) diffractogram, wavelength = xrd.io.read_data(data=data, options=options, index=index)
@ -75,6 +81,9 @@ def plot_diffractogram(data, options={}):
data['diffractogram'][index] = diffractogram data['diffractogram'][index] = diffractogram
data['wavelength'][index] = wavelength data['wavelength'][index] = wavelength
# FIXME This is a quick fix as the image is not reloaded when passing multiple beamline datasets
data['image'] = None
# Sets the xlim if this has not bee specified # Sets the xlim if this has not bee specified
if not options['xlim']: if not options['xlim']:
options['xlim'] = [data['diffractogram'][0][options['x_vals']].min(), data['diffractogram'][0][options['x_vals']].max()] options['xlim'] = [data['diffractogram'][0][options['x_vals']].min(), data['diffractogram'][0][options['x_vals']].max()]
@ -114,7 +123,7 @@ def plot_diffractogram(data, options={}):
options['reflections_data'] = [options['reflections_data']] options['reflections_data'] = [options['reflections_data']]
# Determine number of subplots and height ratios between them # Determine number of subplots and height ratios between them
if len(options['reflections_data']) >= 1: if options['reflections_data'] and len(options['reflections_data']) >= 1:
options = determine_grid_layout(options=options) options = determine_grid_layout(options=options)
@ -331,10 +340,10 @@ def plot_diffractogram_interactive(data, options):
'heatmap_default': {'min': xminmax['heatmap'][0], 'max': xminmax['heatmap'][1], 'value': [xminmax['heatmap'][0], xminmax['heatmap'][1]], 'step': 10} 'heatmap_default': {'min': xminmax['heatmap'][0], 'max': xminmax['heatmap'][1], 'value': [xminmax['heatmap'][0], xminmax['heatmap'][1]], 'step': 10}
}, },
'ylim': { '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%')), 'w': widgets.FloatRangeSlider(value=[yminmax['start'][2], yminmax['start'][3]], min=yminmax['start'][0], max=yminmax['start'][1], step=0.01, layout=widgets.Layout(width='95%')),
'state': 'heatmap' if options['heatmap'] else 'diff', '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}, 'diff_default': {'min': yminmax['diff'][0], 'max': yminmax['diff'][1], 'value': [yminmax['diff'][2], yminmax['diff'][3]], 'step': 0.01},
'heatmap_default': {'min': yminmax['heatmap'][0], 'max': yminmax['heatmap'][1], 'value': [yminmax['heatmap'][0], yminmax['heatmap'][1]], 'step': 0.1} 'heatmap_default': {'min': yminmax['heatmap'][0], 'max': yminmax['heatmap'][1], 'value': [yminmax['heatmap'][0], yminmax['heatmap'][1]], 'step': 0.01}
} }
} }
@ -356,7 +365,12 @@ def plot_diffractogram_interactive(data, options):
w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_diffractogram), data=widgets.fixed(data), options=widgets.fixed(options), w = widgets.interactive(btp.ipywidgets_update, func=widgets.fixed(plot_diffractogram), data=widgets.fixed(data), options=widgets.fixed(options),
scatter=widgets.ToggleButton(value=False), scatter=widgets.ToggleButton(value=False),
line=widgets.ToggleButton(value=True), line=widgets.ToggleButton(value=True),
xlim=options['widgets']['xlim']['w']) 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=options['widgets']['ylim']['w'],
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'))
options['widget'] = w options['widget'] = w