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:
''' 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':
# Creates masks for charge and discharge curves
chg_mask = df['current'] >= 0
dchg_mask = df['current'] < 0
# Loop through all the cycling steps, change the current and capacities in the
for i in range(df["count"].max()):
sub_df = df.loc[df['count'] == i+1]
sub_df_chg = sub_df.loc[chg_mask]
#sub_df_dchg = sub_df.loc[dchg_mask]
# get indices where the program changed
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:
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:
for i in chg_indices:
add = df['specific_capacity'].iloc[i-1]
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
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.

View file

@ -5,40 +5,55 @@ import pandas as pd
import numpy as np
import math
import ipywidgets as widgets
from IPython.display import display
import nafuma.electrochemistry as ec
import nafuma.plotting as btp
import nafuma.auxillary as aux
def plot_gc(data, options=None):
# 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 = {
'x_vals': 'capacity', 'y_vals': 'voltage',
'which_cycles': 'all',
'charge': True, 'discharge': True,
'colours': None,
'differentiate_charge_discharge': True,
'gradient': False,
'gradient': False,
'interactive': False,
'interactive_session_active': False,
'rc_params': {},
'format_params': {}}
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)
data['cycles'] = ec.io.read_data(data=data, options=options)
if not 'cycles' in data.keys():
data['cycles'] = ec.io.read_data(data=data, options=options)
# Update list of cycles to correct indices
update_cycles_list(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']):
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])
update_labels(options)
print(options['xunit'])
if options['interactive_session_active']:
update_labels(options, force=True)
else:
update_labels(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('_', ' ')
if 'ylabel' not in options.keys():
if 'ylabel' not in options.keys() or force:
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':
options['xunit'] = options['units']['capacity']
elif options['x_vals'] == 'specific_capacity':
@ -78,7 +110,7 @@ def update_labels(options):
options['xunit'] = None
if 'yunit' not in options.keys():
if 'yunit' not in options.keys() or force:
if options['y_vals'] == '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
if 'image' not in data.keys():
if 'image' not in data.keys() or not data['image']:
data['image'] = get_image_array(data['path'][index])
# Instanciate the azimuthal integrator from pyFAI from the calibrant (.poni-file)
ai = pyFAI.load(data['calibrant'])
@ -72,11 +73,15 @@ def integrate_1d(data, options={}, index=0):
if not os.path.isdir(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)
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']:
os.remove(filename)
@ -278,8 +283,12 @@ def read_brml(data, options={}, index=0):
#if 'wavelength' not in data.keys():
# 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)
@ -302,7 +311,11 @@ def read_xy(data, options={}, index=0):
#if 'wavelength' not in data.keys():
# 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:
position = 0
@ -326,6 +339,38 @@ def read_xy(data, options={}, index=0):
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):
beamline_extensions = ['mar3450', 'edf', 'cbf']
@ -342,7 +387,7 @@ def read_data(data, options={}, index=0):
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.
diffractogram['I_org'] = diffractogram['I']
@ -351,6 +396,7 @@ def read_data(data, options={}, index=0):
diffractogram = apply_offset(diffractogram, wavelength, index, options)
diffractogram = translate_wavelengths(data=diffractogram, wavelength=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'].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
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'].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
@ -501,7 +547,7 @@ def translate_wavelengths(data: pd.DataFrame, wavelength: float, to_wavelength=N
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:
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

View file

@ -13,7 +13,6 @@ import nafuma.xrd as xrd
import nafuma.auxillary as aux
import nafuma.plotting as btp
def plot_diffractogram(data, options={}):
''' Plots a diffractogram.
@ -67,7 +66,14 @@ def plot_diffractogram(data, options={}):
if not 'diffractogram' in data.keys():
# Initialise empty list for diffractograms and wavelengths
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'])):
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['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
if not options['xlim']:
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']]
# 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)
@ -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}
},
'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',
'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}
'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.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),
scatter=widgets.ToggleButton(value=False),
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