# -*- coding: utf-8 -*-
"""
Utilities for static and interactive visualization of Band Excitation Scanning Probe Microscopy datasets
Created on Thu Jan 05 13:29:12 2017
@author: Chris R. Smith, Suhas Somnath
"""
from __future__ import division, print_function, absolute_import, unicode_literals
import os
from warnings import warn
import ipywidgets as widgets
import numpy as np
from IPython.display import display
from matplotlib import pyplot as plt
from sidpy.viz.plot_utils import plot_curves, plot_map_stack, get_cmap_object, plot_map, set_tick_font_size, \
plot_complex_spectra
from sidpy.viz.jupyter_utils import save_fig_filebox_button
from sidpy.hdf.hdf_utils import get_auxiliary_datasets, get_attr
from pyUSID.io.hdf_utils import reshape_to_n_dims, get_sort_order, \
get_dimensionality, get_source_dataset
from pyUSID import USIDataset
from ..analysis.utils.be_loop import loop_fit_function
from ..analysis.utils.be_sho import SHOfunc
[docs]
def visualize_sho_results(h5_main, save_plots=True, show_plots=True, cmap=None,
expt_type=None, meas_type=None, field_mode=None):
"""
Plots some loops, amplitude, phase maps for BE-Line and BEPS datasets.\n
Note: The file MUST contain SHO fit gusses at the very least
Parameters
----------
h5_main : HDF5 Dataset
dataset to be plotted
save_plots : (Optional) Boolean
Whether or not to save plots to files in the same directory as the h5 file
show_plots : (Optional) Boolean
Whether or not to display the plots on the screen
cmap : String, or matplotlib.colors.LinearSegmentedColormap object (Optional)
Requested color map
expt_type : str, Optional
Type of data. This is an attribute written to the HDF5 file at the
root level by either the translator or the acquisition software.
Accepted values are: 'BEPSData', 'BELineData', 'BERelaxData',
'cKPFMData'
Default - this function will attempt to extract this metadata from the
HDF5 file
meas_type: str, Optional
Type of measurement. Accepted values are:
'AC modulation mode with time reversal' or 'DC modulation mode'
This is an attribute embedded under the "Measurement" group with the
following key: 'VS_mode'. Default - this function will attempt to
extract this metadata from the HDF5 file
field_mode : str, Optional
Mode in which measurements were made. Accepted values are:
'in and out-of-field',
This is an attribute at the "Measurement" group under the following key:
'VS_measure_in_field_loops'. Default - this function will attempt to
extract this metadata from the HDF5 file
Returns
-------
None
"""
# TODO: This function needs to be cleaned up and modularized, not perform as many hard checks for attributes; rather accept attributes as kwargs; return the figure object instead of writing to file, etc.
cmap = get_cmap_object(cmap)
def __plot_loops_maps(ac_vec, resp_mat, grp_name, win_title, spec_var_title, meas_var_title, save_plots,
folder_path, basename, num_rows, num_cols):
if isinstance(grp_name, str):
grp_name = grp_name + '_'
else:
grp_name = ''
plt_title = grp_name + win_title + '_Loops'
fig, ax = plot_curves(ac_vec, resp_mat, evenly_spaced=True, num_plots=25, x_label=spec_var_title,
y_label=meas_var_title, subtitle_prefix='Position', title=plt_title)
if save_plots:
fig.savefig(os.path.join(folder_path, basename + '_' + plt_title + '.png'), format='png', dpi=300)
plt_title = grp_name + '_' + win_title + '_Snaps'
fig, axes = plot_map_stack(resp_mat.reshape(num_rows, num_cols, resp_mat.shape[1]),
color_bar_mode="each", evenly_spaced=True, subtitle='UDVS Step #',
title=plt_title, cmap=cmap)
if save_plots:
fig.savefig(os.path.join(folder_path, basename + '_' + plt_title + '.png'), format='png', dpi=300)
return fig
print('Creating plots of SHO Results from {}.'.format(h5_main.name))
h5_file = h5_main.file
if not isinstance(expt_type, str):
expt_type = get_attr(h5_file, 'data_type')
if expt_type not in ['BEPSData', 'BELineData', 'BERelaxData', 'cKPFMData']:
warn('Unsupported data format')
return
isBEPS = expt_type != 'BELineData'
(folder_path, basename) = os.path.split(h5_file.filename)
basename, _ = os.path.splitext(basename)
# This is OK
sho_grp = h5_main.parent
# TODO: This makes too many assumptions about the file structure
chan_grp = h5_file['/'.join(sho_grp.name[1:].split('/')[:2])]
meas_grp = chan_grp.parent
# TODO: This makes too many assumptions about the file structure
grp_name = None
if meas_type is None and field_mode is None:
grp_name = '_'.join(chan_grp.name[1:].split('/'))
grp_name = '_'.join([grp_name, sho_grp.name.split('/')[-1].split('-')[0], h5_main.name.split('/')[-1]])
try:
h5_pos = h5_main.h5_pos_inds
except KeyError:
print('No Position_Indices found as attribute of {}'.format(h5_main.name))
print('Rows and columns will be calculated from dataset shape.')
num_rows = int(np.floor((np.sqrt(h5_main.shape[0]))))
num_cols = int(np.reshape(h5_main, [num_rows, -1, h5_main.shape[1]]).shape[1])
else:
num_rows, num_cols = h5_main.pos_dim_sizes
try:
h5_spec_vals = h5_file[get_attr(h5_main, 'Spectroscopic_Values')]
except Exception:
raise
# Assume that there's enough memory to load all the guesses into memory
amp_mat = h5_main['Amplitude [V]'] * 1000 # convert to mV ahead of time
freq_mat = h5_main['Frequency [Hz]'] / 1000
q_mat = h5_main['Quality Factor']
phase_mat = h5_main['Phase [rad]']
rsqr_mat = h5_main['R2 Criterion']
fig_list = list()
if isBEPS:
if not isinstance(meas_type, str):
meas_type = meas_grp.attrs['VS_mode']
# basically 3 kinds for now - DC/current, AC, UDVS - lets ignore this
if meas_type == 'load user defined VS Wave from file':
warn('Not handling custom experiments for now')
# h5_file.close()
return
# Plot amplitude and phase maps at one or more UDVS steps
if meas_type == 'AC modulation mode with time reversal':
center = int(h5_spec_vals.shape[1] * 0.5)
ac_vec = np.squeeze(h5_spec_vals[h5_spec_vals.attrs['AC_Amplitude']][:, 0:center])
forw_resp = np.squeeze(amp_mat[:, slice(0, center)])
rev_resp = np.squeeze(amp_mat[:, slice(center, None)])
for win_title, resp_mat in zip(['Forward', 'Reverse'], [forw_resp, rev_resp]):
fig_list.append(__plot_loops_maps(ac_vec, resp_mat, grp_name, win_title, 'AC Amplitude', 'Amplitude',
save_plots, folder_path, basename, num_rows, num_cols))
else:
# plot loops at a few locations
dc_vec = np.squeeze(h5_spec_vals[h5_spec_vals.attrs['DC_Offset']])
if not isinstance(field_mode, str):
field_mode = meas_grp.attrs['VS_measure_in_field_loops']
if field_mode == 'in and out-of-field':
dc_vec = np.squeeze(dc_vec[slice(0, None, 2)])
in_phase = np.squeeze(phase_mat[:, slice(0, None, 2)])
in_amp = np.squeeze(amp_mat[:, slice(0, None, 2)])
out_phase = np.squeeze(phase_mat[:, slice(1, None, 2)])
out_amp = np.squeeze(amp_mat[:, slice(1, None, 2)])
for win_title, resp_mat in zip(['In_Field', 'Out_of_Field'], [in_phase * in_amp, out_phase * out_amp]):
fig_list.append(__plot_loops_maps(dc_vec, resp_mat, grp_name, win_title, 'DC Bias',
'Piezoresponse (a.u.)', save_plots, folder_path,
basename, num_rows, num_cols))
else:
fig_list.append(__plot_loops_maps(dc_vec, phase_mat * amp_mat, grp_name, '', 'DC Bias',
'Piezoresponse (a.u.)', save_plots, folder_path, basename,
num_rows, num_cols))
else: # BE-Line can only visualize the amplitude and phase maps:
amp_mat = amp_mat.reshape(num_rows, num_cols)
freq_mat = freq_mat.reshape(num_rows, num_cols)
q_mat = q_mat.reshape(num_rows, num_cols)
phase_mat = phase_mat.reshape(num_rows, num_cols)
rsqr_mat = rsqr_mat.reshape(num_rows, num_cols)
fig_ms, ax_ms = plot_map_stack(np.dstack((amp_mat, freq_mat, q_mat, phase_mat, rsqr_mat)).T,
num_comps=5, color_bar_mode='each', title=grp_name,
subtitle=['Amplitude (mV)', 'Frequency (kHz)', 'Quality Factor', 'Phase (deg)',
'R^2 Criterion'], cmap=cmap)
fig_list.append(fig_ms)
if save_plots:
if grp_name is None:
grp_name = ''
else:
grp_name = grp_name + '_'
plt_path = os.path.join(folder_path, basename + '_' + grp_name + 'Maps.png')
fig_ms.savefig(plt_path, format='png', dpi=300)
if show_plots:
plt.show()
return fig_list
[docs]
def plot_loop_guess_fit(vdc, ds_proj_loops, ds_guess, ds_fit, title=''):
"""
Plots the loop guess, fit, source projected loops for a single cycle
Parameters
----------
vdc - 1D float numpy array
DC offset vector (unshifted)
ds_proj_loops - 2D numpy array
Projected loops arranged as [position, vdc]
ds_guess - 1D compound numpy array
Loop guesses arranged as [position]
ds_fit - 1D compound numpy array
Loop fits arranged as [position]
title - (Optional) String / unicode
Title for the figure
Returns
----------
fig - matplotlib.pyplot.figure object
Figure handle
axes - 2D array of matplotlib.pyplot.axis handles
handles to axes in the 2d figure
"""
shift_ind = int(-1 * len(vdc) / 4)
vdc_shifted = np.roll(vdc, shift_ind)
loops_shifted = np.roll(ds_proj_loops, shift_ind, axis=1)
num_plots = np.min([5, int(np.sqrt(ds_proj_loops.shape[0]))])
fig, axes = plt.subplots(nrows=num_plots, ncols=num_plots, figsize=(18, 18))
positions = np.linspace(0, ds_proj_loops.shape[0] - 1, num_plots ** 2, dtype=np.int)
for ax, pos in zip(axes.flat, positions):
ax.plot(vdc_shifted, loops_shifted[pos, :], 'k', label='Raw')
ax.plot(vdc_shifted, loop_fit_function(vdc_shifted, np.array(list(ds_guess[pos]))), 'g', label='guess')
ax.plot(vdc_shifted, loop_fit_function(vdc_shifted, np.array(list(ds_fit[pos]))), 'r--', label='Fit')
ax.set_xlabel('V_DC (V)')
ax.set_ylabel('PR (a.u.)')
ax.set_title('Position ' + str(pos))
ax.legend()
fig.suptitle(title)
fig.tight_layout()
return fig, axes
[docs]
def jupyter_visualize_beps_sho(pc_sho_dset, step_chan, resp_func=None, resp_label='Response', cmap=None, verbose=False):
"""
Jupyer notebook ONLY function. Sets up an interactive visualizer for viewing SHO fitted BEPS data.
Currently, this is limited to DC and AC spectroscopy datasets.
Parameters
----------
pc_sho_dset : USIDataset
dataset to be plotted
step_chan : string / unicode
Name of the channel that forms the primary spectroscopic axis (eg - DC offset)
resp_func : function (optional)
Function to apply to the spectroscopic data. Currently, DC spectroscopy uses A*cos(phi) and AC spectroscopy
uses A
resp_label : string / unicode (optional)
Label for the response (y) axis.
cmap : String, or matplotlib.colors.LinearSegmentedColormap object (Optional)
Requested color map
verbose : bool, optional
Whether or not to print logs for debugging. Default = False
"""
cmap = get_cmap_object(cmap)
h5_sho_spec_inds = pc_sho_dset.h5_spec_inds
h5_sho_spec_vals = pc_sho_dset.h5_spec_vals
spec_nd, _ = reshape_to_n_dims(h5_sho_spec_inds, h5_spec=h5_sho_spec_inds, verbose=verbose)
sho_spec_dims = pc_sho_dset.spec_dim_sizes
sho_spec_labels = pc_sho_dset.spec_dim_labels
h5_pos_inds = pc_sho_dset.h5_pos_inds
pos_nd, _ = reshape_to_n_dims(h5_pos_inds, h5_pos=h5_pos_inds, verbose=verbose)
pos_dims = pc_sho_dset.pos_dim_sizes
pos_labels = pc_sho_dset.pos_dim_labels
# reshape to X, Y, step, all others
spec_step_dim_ind = sho_spec_labels.index(step_chan)
step_dim_ind = len(pos_dims) + spec_step_dim_ind
# move the step dimension to be the first after all position dimensions
rest_sho_dim_order = list(range(len(pos_dims), len(pc_sho_dset.n_dim_sizes)))
rest_sho_dim_order.remove(step_dim_ind)
new_order = list(range(len(pos_dims))) + [step_dim_ind] + rest_sho_dim_order
# Transpose the 3D dataset to this shape:
guess_nd_data = pc_sho_dset.get_n_dim_form()
guess_nd_data = np.transpose(guess_nd_data, new_order)
# Now move the step dimension to the front for the spec labels as well
new_spec_order = list(range(len(sho_spec_labels)))
new_spec_order.remove(spec_step_dim_ind)
new_spec_order = [spec_step_dim_ind] + new_spec_order
# new_spec_labels = sho_spec_labels[new_spec_order]
new_spec_dims = np.array(sho_spec_dims)[new_spec_order]
# Now collapse all additional dimensions
final_guess_shape = pos_dims + [new_spec_dims[0]] + [-1]
sho_dset_collapsed = np.reshape(guess_nd_data, final_guess_shape).squeeze()
# Get the bias matrix:
bias_mat, _ = reshape_to_n_dims(h5_sho_spec_vals, h5_spec=h5_sho_spec_inds, verbose=verbose)
bias_mat = np.transpose(bias_mat[spec_step_dim_ind],
new_spec_order).reshape(sho_dset_collapsed.shape[len(pos_dims):])
if bias_mat.ndim == 1:
bias_mat = np.atleast_2d(bias_mat).T
# This is just the visualizer:
sho_quantity = 'Amplitude [V]'
step_ind = 0
row_ind = 1
col_ind = 1
def dc_spectroscopy_func(resp_vec):
return resp_vec['Amplitude [V]'] * np.cos(resp_vec['Phase [rad]']) * 1E+3
def ac_spectroscopy_func(resp_vec):
return resp_vec['Amplitude [V]']
if resp_func is None:
if step_chan == 'DC_Offset':
resp_func = dc_spectroscopy_func
resp_label = 'A cos($\phi$) (a. u.)'
else:
resp_func = ac_spectroscopy_func
resp_label = 'Amplitude (a. u.)'
not_step_chan = sho_spec_labels.copy()
not_step_chan.remove(step_chan)
spatial_dict = {step_chan: [step_ind]}
resp_dict = {pos_labels[-1]: row_ind,
pos_labels[-2]: col_ind}
for key in pos_labels[:-2]:
spatial_dict[key] = 0
resp_dict[key] = 0
if not_step_chan is not None:
for key in not_step_chan:
spatial_dict[key] = 0
if verbose:
print('Starting slicing dictionary for spatial plot: {}'.format(spatial_dict))
print('Starting slicing dictionary for spectroscopic plot: {}'.format(resp_dict))
spatial_map = pc_sho_dset.slice(spatial_dict, as_scalar=False, verbose=verbose)[0][sho_quantity].squeeze()
resp_vec = resp_func(pc_sho_dset.slice(resp_dict, as_scalar=False, verbose=verbose)[0].reshape(bias_mat.shape))
fig = plt.figure(figsize=(12, 8))
ax_bias = plt.subplot2grid((3, 2), (0, 0), colspan=1, rowspan=1)
ax_map = plt.subplot2grid((3, 2), (1, 0), rowspan=2)
ax_loop = plt.subplot2grid((3, 2), (0, 1), colspan=1, rowspan=3)
ax_bias.plot(bias_mat[:, 0])
ax_bias.set_xlabel('Bias Step')
ax_bias.set_ylabel(step_chan.replace('_', ' ') + ' (V)')
bias_slider = ax_bias.axvline(x=step_ind, color='r')
img_map, img_cmap = plot_map(ax_map, spatial_map.T, show_xy_ticks=True, cmap=cmap)
map_title = '{} - {}={}'.format(sho_quantity, step_chan, bias_mat[step_ind][0])
ax_map.set_xlabel(pos_labels[-1])
ax_map.set_ylabel(pos_labels[-2])
ax_map.set_title(map_title)
crosshair = ax_map.plot(row_ind, col_ind, 'k+')[0]
ax_loop.axvline(x=0, color='gray', linestyle='--')
ax_loop.axhline(y=0, color='gray', linestyle='--')
line_handles = ax_loop.plot(bias_mat, resp_vec)
ax_loop.set_xlabel(step_chan.replace('_', ' ') + ' (V)')
ax_loop.set_ylabel(resp_label)
fig.tight_layout()
plt.show()
# Build sliders for any extra Position Dimensions
pos_sliders = dict()
for ikey, key in enumerate(pos_labels[:-2]):
pos_sliders[key] = widgets.IntSlider(value=0, min=0, max=pos_dims[ikey] - 1,
step=1, description='{} Step:'.format(key),
continuous_update=False)
def update_sho_plots(sho_quantity, step_ind):
bias_slider.set_xdata((step_ind, step_ind))
spatial_dict[step_chan] = step_ind
if verbose:
print('Updating spatial dict as: {}'.format(spatial_dict))
spatial_map = pc_sho_dset.slice(spatial_dict, as_scalar=False, verbose=verbose)[0][sho_quantity].squeeze()
map_title = '{} - {}={}'.format(sho_quantity, step_chan, bias_mat[step_ind][0])
ax_map.set_title(map_title)
img_map.set_data(spatial_map.T)
spat_mean = np.mean(spatial_map)
spat_std = np.std(spatial_map)
img_map.set_clim(vmin=spat_mean - 3 * spat_std, vmax=spat_mean + 3 * spat_std)
def update_resp_plot(resp_dict):
if verbose:
print('Updating spectroscopic dict as: {}'.format(resp_dict))
resp_vec = resp_func(pc_sho_dset.slice(resp_dict, as_scalar=False, verbose=verbose)[0].reshape(bias_mat.shape)).T
for line_handle, data in zip(line_handles, resp_vec):
line_handle.set_ydata(data)
ax_loop.relim()
ax_loop.autoscale_view()
def pos_picker(event):
if not img_map.axes.in_axes(event):
return
xdata = int(round(event.xdata))
ydata = int(round(event.ydata))
resp_dict[pos_labels[-1]] = xdata
resp_dict[pos_labels[-2]] = ydata
crosshair.set_xdata(xdata)
crosshair.set_ydata(ydata)
update_resp_plot(resp_dict)
fig.canvas.draw()
def pos_slider_update(slider):
for key in pos_labels[:-2]:
spatial_dict[key] = pos_sliders[key].value
resp_dict[key] = pos_sliders[key].value
step = bias_step_picker.value
sho_quantity = sho_quantity_picker.value
update_resp_plot(resp_dict)
update_sho_plots(sho_quantity, step)
fig.canvas.draw()
slider_dict = dict()
slider_dict['Bias Step'] = (0, bias_mat.shape[0] - 1, 1)
sho_quantity_picker = widgets.Dropdown(options=list(sho_dset_collapsed.dtype.names[:-1]),
description='SHO Quantity')
bias_step_picker = widgets.IntSlider(min=0, max=bias_mat.shape[0] - 1, step=1,
description='Bias Step')
fig_filename, _ = os.path.splitext(pc_sho_dset.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
for key, slider in pos_sliders.items():
widgets.interact(pos_slider_update, slider=slider)
cid = img_map.figure.canvas.mpl_connect('button_press_event', pos_picker)
widgets.interact(update_sho_plots, sho_quantity=sho_quantity_picker, step_ind=bias_step_picker)
return fig
[docs]
def jupyter_visualize_be_spectrograms(pc_main, cmap=None):
"""
Jupyer notebook ONLY function. Sets up a simple visualzier for visualizing raw BE data.
Sliders for position indices can be used to visualize BE spectrograms (frequency, UDVS step).
In the case of 2 spatial dimensions, a spatial map will be provided as well
Parameters
----------
pc_main : USIDataset
Raw Band Excitation dataset
cmap : String, or matplotlib.colors.LinearSegmentedColormap object (Optional)
Requested color map
"""
cmap = get_cmap_object(cmap)
h5_pos_inds = pc_main.h5_pos_inds
pos_dims = pc_main.pos_dim_sizes
pos_labels = pc_main.pos_dim_labels
h5_spec_vals = pc_main.h5_spec_vals
h5_spec_inds = pc_main.h5_spec_inds
spec_dims = pc_main.spec_dim_sizes
spec_labels = pc_main.spec_dim_labels
ifreq = spec_labels.index('Frequency')
freqs_nd = reshape_to_n_dims(h5_spec_vals, h5_spec=h5_spec_inds)[0][ifreq].squeeze()
freqs_2d = freqs_nd.reshape(freqs_nd.shape[0], -1) / 1000 # Convert to kHz
num_udvs_steps = int(np.prod([spec_dims[idim] for idim in range(len(spec_dims)) if idim != ifreq]))
if len(pos_dims) >= 2:
# Build initial slice dictionaries
spatial_slice_dict = {'X': slice(None), 'Y': slice(None)}
for key in pos_labels:
if key in spatial_slice_dict.keys():
continue
else:
spatial_slice_dict[key] = [0]
spectrogram_slice_dict = {key: [0] for key in pos_labels}
spatial_slice, _ = pc_main._get_pos_spec_slices(slice_dict=spatial_slice_dict)
x_size = pos_dims[-1]
y_size = pos_dims[-2]
spatial_map = np.abs(np.reshape(pc_main[spatial_slice, 0], (y_size, x_size)))
spectrogram = np.reshape(pc_main[0], (num_udvs_steps, -1))
fig, axes = plt.subplots(ncols=3, figsize=(12, 4), subplot_kw={'adjustable': 'box'})
spatial_img, spatial_cbar = plot_map(axes[0], np.abs(spatial_map), cmap=cmap)
axes[0].set_aspect('equal')
axes[0].set_xlabel(pos_labels[-1])
axes[0].set_ylabel(pos_labels[-2])
xdata = int(0.5 * x_size)
ydata = int(0.5 * y_size)
crosshair = axes[0].plot(xdata, ydata, 'k+')[0]
if len(spec_dims) > 1:
amp_img, amp_cbar = plot_map(axes[1], np.abs(spectrogram), show_xy_ticks=True, cmap=cmap,
extent=[freqs_2d[0, 0], freqs_2d[-1, 0], 0, num_udvs_steps])
phase_img, phase_cbar = plot_map(axes[2], np.angle(spectrogram), show_xy_ticks=True, cmap=cmap,
extent=[freqs_2d[0, 0], freqs_2d[-1, 0], 0, num_udvs_steps])
phase_img.set_clim(vmin=-np.pi, vmax=np.pi)
for axis in axes[1:3]:
axis.set_ylabel('BE step')
axis.axis('tight')
x0, x1 = (freqs_2d[0, 0], freqs_2d[-1, 0])
y0, y1 = (0, num_udvs_steps)
axis.set_aspect(np.abs(x1 - x0) / np.abs(y1 - y0))
else:
# BE-Line
axes[1].set_ylabel('Amplitude (a. u.)')
axes[2].set_ylabel('Phase (rad)')
spectrogram = np.squeeze(spectrogram)
amp_img = axes[1].plot(np.abs(spectrogram))[0]
phase_img = axes[2].plot(np.angle(spectrogram))[0]
amp_full = np.abs(pc_main[()])
amp_mean = np.mean(amp_full)
amp_std = np.std(amp_full)
st_devs = 4
axes[1].set_ylim([0, amp_mean + st_devs * amp_std])
axes[2].set_ylim([-np.pi, np.pi])
pos_heading = pos_labels[-1] + ': ' + str(xdata) + ', ' + \
pos_labels[-2] + ': ' + str(ydata) + ', '
for dim_name in pos_labels[-3::-1]:
pos_heading += dim_name + ': ' + str(spatial_slice_dict[dim_name]) + ', '
axes[1].set_title('Amplitude \n' + pos_heading)
axes[1].set_xlabel('Frequency (kHz)')
axes[2].set_title('Phase \n' + pos_heading)
axes[2].set_xlabel('Frequency (kHz)')
fig.tight_layout()
fig_filename, _ = os.path.splitext(pc_main.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
# Build sliders for any extra Position Dimensions
pos_sliders = dict()
for ikey, key in enumerate(pos_labels[:-2]):
pos_sliders[key] = widgets.IntSlider(value=0, min=0, max=pos_dims[ikey] - 1,
step=1, description='{} Step:'.format(key),
continuous_update=False)
def get_spatial_slice():
xdata, ydata = crosshair.get_xydata().squeeze()
spatial_slice_dict[pos_labels[-1]] = [int(xdata)]
spatial_slice_dict[pos_labels[-2]] = [int(ydata)]
for key in pos_labels[:-2]:
spatial_slice_dict[key] = [pos_sliders[key].value]
spatial_slice, _ = pc_main._get_pos_spec_slices(slice_dict=spatial_slice_dict)
return spatial_slice
def spec_index_unpacker(step):
spatial_slice_dict[pos_labels[-1]] = slice(None)
spatial_slice_dict[pos_labels[-2]] = slice(None)
for key in pos_labels[:-2]:
spatial_slice_dict[key] = [pos_sliders[key].value]
spatial_slice, _ = pc_main._get_pos_spec_slices(slice_dict=spatial_slice_dict)
spatial_map = np.abs(np.reshape(pc_main[spatial_slice, step], (x_size, y_size)))
spatial_img.set_data(spatial_map)
spat_mean = np.mean(spatial_map)
spat_std = np.std(spatial_map)
spatial_img.set_clim(vmin=spat_mean - 3 * spat_std, vmax=spat_mean + 3 * spat_std)
spec_heading = ''
for dim_ind, dim_name in enumerate(spec_labels):
spec_heading += dim_name + ': ' + str(h5_spec_vals[dim_ind, step]) + ', '
axes[0].set_title(spec_heading[:-2])
fig.canvas.draw()
def pos_picker(event):
if not spatial_img.axes.in_axes(event):
return
xdata = int(round(event.xdata))
ydata = int(round(event.ydata))
crosshair.set_xdata(xdata)
crosshair.set_ydata(ydata)
spatial_slice = get_spatial_slice()
pos_heading = pos_labels[-1] + ': ' + str(xdata) + ', ' + \
pos_labels[-2] + ': ' + str(ydata) + ', '
for dim_name in pos_labels[-3::-1]:
pos_heading += dim_name + ': ' + str(spatial_slice_dict[dim_name]) + ', '
axes[1].set_title('Amplitude \n' + pos_heading)
axes[2].set_title('Phase \n' + pos_heading)
spectrogram = np.reshape(pc_main[spatial_slice, :], (num_udvs_steps, -1))
if len(spec_dims) > 1:
amp_map = np.abs(spectrogram)
amp_img.set_data(np.abs(spectrogram))
phase_img.set_data(np.angle(spectrogram))
amp_mean = np.mean(amp_map)
amp_std = np.std(amp_map)
amp_img.set_clim(vmin=amp_mean - 3 * amp_std, vmax=amp_mean + 3 * amp_std)
else:
amp_img.set_ydata(np.abs(spectrogram))
phase_img.set_ydata(np.angle(spectrogram))
amp_cbar.changed()
phase_cbar.changed()
fig.canvas.draw()
def pos_slider_update(slider):
spatial_slice = get_spatial_slice()
step = spec_index_slider.value
spec_index_unpacker(step)
pos_heading = pos_labels[-1] + ': ' + str(xdata) + ', ' + \
pos_labels[-2] + ': ' + str(ydata) + ', '
for dim_name in pos_labels[-3::-1]:
pos_heading += dim_name + ': ' + str(spatial_slice_dict[dim_name]) + ', '
axes[1].set_title('Amplitude \n' + pos_heading)
axes[2].set_title('Phase \n' + pos_heading)
spectrogram = np.reshape(pc_main[spatial_slice, :], (num_udvs_steps, -1))
if len(spec_dims) > 1:
amp_img.set_data(np.abs(spectrogram))
phase_img.set_data(np.angle(spectrogram))
else:
amp_img.set_ydata(np.abs(spectrogram))
phase_img.set_ydata(np.angle(spectrogram))
amp_cbar.changed()
phase_cbar.changed()
fig.canvas.draw()
spec_index_slider = widgets.IntSlider(value=0, min=0, max=pc_main.shape[1], step=1,
description='Step')
cid = spatial_img.figure.canvas.mpl_connect('button_press_event', pos_picker)
widgets.interact(spec_index_unpacker, step=spec_index_slider)
for key, slider in pos_sliders.items():
widgets.interact(pos_slider_update, slider=slider)
# plt.show()
else:
def plot_spectrogram(data, freq_vals):
fig, axes = plt.subplots(ncols=2, figsize=(9, 5), sharey=True)
im_handles = list()
im_handles.append(axes[0].imshow(np.abs(data), cmap=cmap,
extent=[freqs_2d[0, 0], freqs_2d[-1, 0],
data.shape[0], 0],
interpolation='none'))
axes[0].set_title('Amplitude')
axes[0].set_ylabel('BE step')
im_handles.append(axes[1].imshow(np.angle(data), cmap=cmap,
extent=[freqs_2d[0, 0], freqs_2d[-1, 0],
data.shape[0], 0],
interpolation='none'))
axes[1].set_title('Phase')
axes[0].set_xlabel('Frequency index')
axes[1].set_xlabel('Frequency index')
for axis in axes:
axis.axis('tight')
axis.set_ylim(0, data.shape[0])
fig.tight_layout()
return fig, axes, im_handles
fig, axes, im_handles = plot_spectrogram(np.reshape(pc_main[0], (num_udvs_steps, -1)), freqs_2d)
def position_unpacker(**kwargs):
pos_dim_vals = range(len(pos_labels))
for pos_dim_ind, pos_dim_name in enumerate(pos_labels):
pos_dim_vals[pos_dim_ind] = kwargs[pos_dim_name]
pix_ind = pos_dim_vals[0]
for pos_dim_ind in range(1, len(pos_labels)):
pix_ind += pos_dim_vals[pos_dim_ind] * pos_dims[pos_dim_ind - 1]
spectrogram = np.reshape(pc_main[pix_ind], (num_udvs_steps, -1))
im_handles[0].set_data(np.abs(spectrogram))
im_handles[1].set_data(np.angle(spectrogram))
display(fig)
pos_dict = dict()
for pos_dim_ind, dim_name in enumerate(pos_labels):
pos_dict[dim_name] = (0, pos_dims[pos_dim_ind] - 1, 1)
widgets.interact(position_unpacker, **pos_dict)
display(fig)
return fig
[docs]
def jupyter_visualize_beps_loops(h5_projected_loops, h5_loop_guess, h5_loop_fit, step_chan='DC_Offset', cmap=None):
"""
Interactive plotting of the BE Loops
Parameters
----------
h5_projected_loops : h5py.Dataset
Dataset holding the loop projections
h5_loop_guess : h5py.Dataset
Dataset holding the loop guesses
h5_loop_fit : h5py.Dataset
Dataset holding the loop fits
step_chan : str, optional
The name of the Spectroscopic dimension to plot versus. Needs testing.
Default 'DC_Offset'
cmap : String, or matplotlib.colors.LinearSegmentedColormap object (Optional)
Requested color map
Returns
-------
None
"""
cmap = get_cmap_object(cmap)
# Prepare some variables for plotting loops fits and guesses
# Plot the Loop Guess and Fit Results
proj_nd, _ = reshape_to_n_dims(h5_projected_loops)
guess_nd, _ = reshape_to_n_dims(h5_loop_guess)
fit_nd, _ = reshape_to_n_dims(h5_loop_fit)
h5_projected_loops = h5_loop_guess.parent['Projected_Loops']
h5_proj_spec_inds = get_auxiliary_datasets(h5_projected_loops,
aux_dset_name='Spectroscopic_Indices')[-1]
h5_proj_spec_vals = get_auxiliary_datasets(h5_projected_loops,
aux_dset_name='Spectroscopic_Values')[-1]
h5_pos_inds = get_auxiliary_datasets(h5_projected_loops,
aux_dset_name='Position_Indices')[-1]
pos_nd, _ = reshape_to_n_dims(h5_pos_inds, h5_pos=h5_pos_inds)
pos_dims = list(pos_nd.shape[:h5_pos_inds.shape[1]])
pos_labels = get_attr(h5_pos_inds, 'labels')
# reshape the vdc_vec into DC_step by Loop
spec_nd, _ = reshape_to_n_dims(h5_proj_spec_vals, h5_spec=h5_proj_spec_inds)
loop_spec_dims = np.array(spec_nd.shape[1:])
loop_spec_labels = get_attr(h5_proj_spec_vals, 'labels')
spec_step_dim_ind = np.where(loop_spec_labels == step_chan)[0][0]
# # move the step dimension to be the first after all position dimensions
rest_loop_dim_order = list(range(len(pos_dims), len(proj_nd.shape)))
rest_loop_dim_order.pop(spec_step_dim_ind)
new_order = list(range(len(pos_dims))) + [len(pos_dims) + spec_step_dim_ind] + rest_loop_dim_order
new_spec_order = np.array(new_order[len(pos_dims):], dtype=np.uint32) - len(pos_dims)
# Also reshape the projected loops to Positions-DC_Step-Loop
final_loop_shape = pos_dims + [loop_spec_dims[spec_step_dim_ind]] + [-1]
proj_nd2 = np.moveaxis(proj_nd, spec_step_dim_ind + len(pos_dims), len(pos_dims))
proj_nd_3 = np.reshape(proj_nd2, final_loop_shape)
# Do the same for the guess and fit datasets
guess_3d = np.reshape(guess_nd, pos_dims + [-1])
fit_3d = np.reshape(fit_nd, pos_dims + [-1])
# Get the bias vector:
spec_nd2 = np.moveaxis(spec_nd[spec_step_dim_ind], spec_step_dim_ind, 0)
bias_vec = np.reshape(spec_nd2, final_loop_shape[len(pos_dims):])
# Shift the bias vector and the loops by a quarter cycle
shift_ind = int(-1 * bias_vec.shape[0] / 4)
bias_shifted = np.roll(bias_vec, shift_ind, axis=0)
proj_nd_shifted = np.roll(proj_nd_3, shift_ind, axis=len(pos_dims))
# This is just the visualizer:
loop_field_names = fit_nd.dtype.names
loop_field = loop_field_names[0]
loop_ind = 0
row_ind = 0
col_ind = 0
# Initial plot data
spatial_map = fit_3d[:, :, loop_ind][loop_field]
proj_data = proj_nd_shifted[col_ind, row_ind, :, loop_ind]
bias_data = bias_shifted[:, loop_ind]
guess_data = loop_fit_function(bias_data, np.array(list(guess_3d[col_ind, row_ind, loop_ind])))
fit_data = loop_fit_function(bias_data, np.array(list(fit_3d[col_ind, row_ind, loop_ind])))
fig = plt.figure(figsize=(12, 8))
ax_map = plt.subplot2grid((1, 2), (0, 0), colspan=1, rowspan=1)
ax_loop = plt.subplot2grid((1, 2), (0, 1), colspan=1, rowspan=1)
im_map, im_cbar = plot_map(ax_map, spatial_map.T,
x_vec=np.arange(spatial_map.shape[0]),
y_vec=np.arange(spatial_map.shape[1]),
cmap=cmap)
ax_map.set_xlabel('X')
ax_map.set_ylabel('Y')
ax_map.set_title('{} - Loop {}'.format(loop_field, loop_ind))
crosshair = ax_map.plot(row_ind, col_ind, 'k+')[0]
ax_loop.plot(bias_data, proj_data, 'k', label='Projection')
ax_loop.plot(bias_data, guess_data, 'g', label='Guess')
ax_loop.plot(bias_data, fit_data, 'r--', label='Fit')
line_handles = ax_loop.get_lines()
ax_loop.tick_params(labelleft=False, labelright=True)
ax_loop.yaxis.set_label_position('right')
ax_loop.set_ylabel('PR (a.u.)')
ax_loop.set_xlabel('V_DC (V)')
ax_loop.set_title('Position ({},{})'.format(col_ind, row_ind))
ax_loop.legend()
fig.tight_layout()
plt.show()
fig_filename, _ = os.path.splitext(h5_projected_loops.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
loop_slider = widgets.IntSlider(min=0, max=bias_vec.shape[1] - 1, description='Loop Number')
def update_loop_plots(loop_field, loop_ind):
spatial_map = fit_3d[:, :, loop_ind][loop_field]
im_map.set_data(spatial_map.T)
spat_mean = np.mean(spatial_map)
spat_std = np.std(spatial_map)
im_map.set_clim(vmin=spat_mean - 3 * spat_std, vmax=spat_mean + 3 * spat_std)
ax_map.set_title('{} - Loop {}'.format(loop_field, loop_ind))
xdata, ydata = crosshair.get_xydata().flatten().astype('int')
proj_data = proj_nd_shifted[xdata, ydata, :, loop_ind]
bias_data = bias_shifted[:, loop_ind]
guess_data = loop_fit_function(bias_data, np.array(list(guess_3d[xdata, ydata, loop_ind])))
fit_data = loop_fit_function(bias_data, np.array(list(fit_3d[xdata, ydata, loop_ind])))
for line_handle, data in zip(line_handles, [proj_data, guess_data, fit_data]):
line_handle.set_ydata(data)
ax_loop.set_title('Position ({},{})'.format(xdata, ydata))
ax_loop.relim()
ax_loop.autoscale_view()
fig.canvas.draw()
def pos_picker(event):
if not im_map.axes.in_axes(event):
return
xdata = int(round(event.xdata))
ydata = int(round(event.ydata))
current_pos = {pos_labels[0]: xdata, pos_labels[1]: ydata}
pos_dim_vals = list(range(len(pos_labels)))
for pos_dim_ind, pos_dim_name in enumerate(pos_labels):
pos_dim_vals[pos_dim_ind] = current_pos[pos_dim_name]
crosshair.set_xdata(xdata)
crosshair.set_ydata(ydata)
loop_ind = loop_slider.value
proj_data = proj_nd_shifted[xdata, ydata, :, loop_ind]
bias_data = bias_shifted[:, loop_ind]
guess_data = loop_fit_function(bias_data, np.array(list(guess_3d[xdata, ydata, loop_ind])))
fit_data = loop_fit_function(bias_data, np.array(list(fit_3d[xdata, ydata, loop_ind])))
for line_handle, data in zip(line_handles, [proj_data, guess_data, fit_data]):
line_handle.set_ydata(data)
ax_loop.set_title('Position ({},{})'.format(xdata, ydata))
ax_loop.relim()
ax_loop.autoscale_view()
fig.canvas.draw()
cid = im_map.figure.canvas.mpl_connect('button_press_event', pos_picker)
widgets.interact(update_loop_plots, loop_field=list(fit_nd.dtype.names), loop_ind=loop_slider)
return fig
[docs]
def jupyter_visualize_parameter_maps(h5_loop_parameters, cmap=None, **kwargs):
"""
Interactive plot of the spatial maps of the loop parameters for all cycles.
Parameters
----------
h5_loop_parameters : h5py.Dataset
The dataset containing the loop parameters to be visualized
cmap : str or matplotlib.colors.Colormap
Returns
-------
None
"""
if not isinstance(h5_loop_parameters, USIDataset):
h5_loop_parameters = USIDataset(h5_loop_parameters)
# Get the position and spectroscopic datasets
pos_dims = h5_loop_parameters.pos_dim_sizes
num_cycles = h5_loop_parameters.shape[1]
parameter_names = h5_loop_parameters.dtype.names
parameter_map_stack = np.reshape(h5_loop_parameters[parameter_names[0]],
[pos_dims[0], pos_dims[1], -1])
parameter_map_stack = np.moveaxis(parameter_map_stack, -1, 0)
loop_spec_labs = h5_loop_parameters.spec_dim_labels
kwargs.update({'cmap': get_cmap_object(cmap)})
map_titles = list()
for icycle in range(num_cycles):
title_list = list()
for label in loop_spec_labs:
val = h5_loop_parameters.get_spec_values(label)
title_list.append('{}: {}'.format(label, val))
map_titles.append(' - '.join(title_list))
fig, axes = plot_map_stack(parameter_map_stack, num_comps=num_cycles, color_bar_mode='each',
subtitle=map_titles, title='Maps of Loop Parameter {}'.format(parameter_names[0]),
**kwargs)
def update_loop_maps(parameter_name):
parameter_map_stack = np.reshape(h5_loop_parameters[parameter_name],
[pos_dims[0], pos_dims[1], -1])
parameter_map_stack = np.moveaxis(parameter_map_stack, -1, 0)
print('parameter map stack size is ', parameter_map_stack.shape)
fig.suptitle('Maps of Loop Parameter {}'.format(parameter_name))
# Loop over all axes
for icycle, ax_cycle in enumerate(axes[:num_cycles]):
image = ax_cycle.get_images()[0]
image.set_data(parameter_map_stack[icycle,:, :])
image.set_clim(vmin=np.min(parameter_map_stack[icycle, :, :]),
vmax=np.max(parameter_map_stack[icycle, :, :]))
fig.canvas.draw()
plt.show()
fig_filename, _ = os.path.splitext(h5_loop_parameters.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
widgets.interact(update_loop_maps, parameter_name=list(parameter_names))
return fig
[docs]
def jupyter_visualize_loop_sho_raw_comparison(h5_loop_parameters, cmap=None):
"""
Parameters
----------
h5_loop_parameters
cmap : str or matplotlib.colors.Colormap
Returns
-------
"""
# Find the precursor datasets used to calculate these parameters
h5_loop_grp = h5_loop_parameters.parent
h5_loop_projections = h5_loop_grp['Projected_Loops']
h5_loop_fit = h5_loop_grp['Fit']
h5_loop_guess = h5_loop_grp['Guess']
h5_sho_grp = h5_loop_grp.parent
h5_sho_fit = h5_sho_grp['Fit']
h5_sho_guess = h5_sho_grp['Guess']
h5_main = get_source_dataset(h5_sho_grp)
# Now get the needed ancillary datasets for each main dataset
h5_pos_inds = get_auxiliary_datasets(h5_loop_parameters, 'Position_Indices')[0]
h5_pos_vals = get_auxiliary_datasets(h5_loop_parameters, 'Position_Values')[0]
pos_order = get_sort_order(np.transpose(h5_pos_inds))
pos_dims = get_dimensionality(np.transpose(h5_pos_inds), pos_order)
pos_labs = get_attr(h5_pos_inds, 'labels')
h5_loop_spec_inds = get_auxiliary_datasets(h5_loop_parameters, 'Spectroscopic_Indices')[0]
h5_loop_spec_vals = get_auxiliary_datasets(h5_loop_parameters, 'Spectroscopic_Values')[0]
loop_spec_order = get_sort_order(h5_loop_spec_inds)
loop_spec_dims = get_dimensionality(h5_loop_spec_inds, loop_spec_order)
loop_spec_labs = get_attr(h5_loop_spec_inds, 'labels')
h5_sho_spec_inds = h5_sho_fit.h5_spec_inds
h5_sho_spec_vals = h5_sho_fit.h5_spec_vals
sho_spec_order = get_sort_order(h5_sho_spec_inds)
sho_spec_dims = get_dimensionality(h5_sho_spec_inds, sho_spec_order)
sho_spec_labs = get_attr(h5_sho_spec_inds, 'labels')
h5_main_spec_inds = h5_main.h5_spec_inds
h5_main_spec_vals = h5_main.h5_spec_vals
main_spec_order = get_sort_order(h5_main_spec_inds)
main_spec_dims = get_dimensionality(h5_main_spec_inds, main_spec_order)
main_spec_labs = get_attr(h5_main_spec_inds, 'labels')
'''
Select the initial plotting slices
'''
loop_parameter_names = h5_loop_parameters.dtype.names
loop_num_cycles = h5_loop_parameters.shape[1]
loop_parameter_spec_labs = get_attr(h5_loop_spec_vals, 'labels')
sho_bias_dim = np.argwhere(sho_spec_labs[sho_spec_order] == 'DC_Offset').squeeze()
steps_per_loop = sho_spec_dims[sho_bias_dim]
main_bias_dim = np.argwhere(main_spec_labs[main_spec_order] == 'DC_Offset').squeeze()
selected_loop_parm = loop_parameter_names[0]
selected_loop_cycle = 0
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
selected_loop_pos = int(pos_dims[0] / 2), int(pos_dims[1] / 2)
selected_step = int(steps_per_loop / 2)
'''
Get the bias vector to be plotted against
'''
loop_bias_vec = h5_sho_spec_vals[get_attr(h5_sho_spec_vals, 'DC_Offset')].squeeze()
shift_ind = int(-1 * steps_per_loop / 4)
loop_bias_vec = loop_bias_vec.reshape(sho_spec_dims)
loop_bias_vec = np.moveaxis(loop_bias_vec, sho_bias_dim, 0).reshape(sho_spec_dims[sho_bias_dim], -1)
loop_bias_vec = np.roll(loop_bias_vec.reshape(steps_per_loop, -1), shift_ind, axis=0)
'''
Get the frequency vector to be plotted against
'''
full_w_vec = h5_main_spec_vals[h5_main_spec_vals.attrs['Frequency']]
full_w_vec, _ = reshape_to_n_dims(full_w_vec, h5_spec=h5_main_spec_inds)
full_w_vec = full_w_vec.squeeze()
'''
Define functions to get the data
'''
def _get_loop_map(selected_loop_parm, selected_loop_cycle):
# Build the map of the chosen loop parameter
loop_parameter_map = np.reshape(h5_loop_parameters[selected_loop_parm, :, selected_loop_cycle],
[pos_dims[0], pos_dims[1]])
# Also create the title string for the map
loop_map_title = list()
for label in loop_parameter_spec_labs:
val = h5_loop_spec_vals[get_attr(h5_loop_spec_vals, label)].squeeze()[selected_loop_cycle]
loop_map_title.append('{}: {}'.format(label, val))
return loop_parameter_map, loop_map_title
def _get_loops(selected_loop_cycle, selected_loop_pos):
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
# Now build the loop plot for the selected position in the loop map
selected_loop_bias_vec = loop_bias_vec[:, selected_loop_cycle]
pos_ind = np.ravel_multi_index(selected_loop_pos, pos_dims)
loop_proj_vec = h5_loop_projections[pos_ind].reshape(sho_spec_dims[::-1])
loop_proj_vec = np.moveaxis(loop_proj_vec, sho_bias_dim, -1)[selected_loop_ndims]
loop_proj_vec = np.roll(loop_proj_vec, shift_ind)
loop_guess_vec = loop_fit_function(selected_loop_bias_vec,
h5_loop_guess[pos_ind, selected_loop_cycle].tolist())
loop_fit_vec = loop_fit_function(selected_loop_bias_vec,
h5_loop_fit[pos_ind, selected_loop_cycle].tolist())
return selected_loop_bias_vec, loop_proj_vec, loop_guess_vec, loop_fit_vec
def _get_sho(selected_loop_pos, selected_step, selected_loop_cycle):
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
# get the SHO Guess and Fit and Raw Data for the selected position, cycle, and step
pos_ind = np.ravel_multi_index(selected_loop_pos, pos_dims)
# Get the frequency vector for the selected step
w_vec = np.moveaxis(full_w_vec, main_bias_dim - len(pos_dims), -1)[selected_step][selected_loop_ndims]
# Get the slice of the sho guess and fit
sho_guess = h5_sho_guess[pos_ind].reshape(sho_spec_dims[::-1])
sho_guess = np.moveaxis(sho_guess, sho_bias_dim, -1)[selected_loop_ndims][selected_step]
sho_guess = SHOfunc(sho_guess, w_vec)
sho_fit = h5_sho_fit[pos_ind].reshape(sho_spec_dims[::-1])
sho_fit = np.moveaxis(sho_fit, sho_bias_dim, -1)[selected_loop_ndims][selected_step]
sho_fit = SHOfunc(sho_fit, w_vec)
# Get the slice of the Raw Data
raw_data_vec, _ = reshape_to_n_dims(np.atleast_2d(h5_main[pos_ind]), h5_spec=h5_main_spec_inds)
raw_data_vec = np.moveaxis(raw_data_vec.squeeze(),
main_bias_dim - len(pos_dims), -1)[selected_step][selected_loop_ndims]
return w_vec, sho_guess, sho_fit, raw_data_vec
'''
Get the starting values
'''
loop_parm_map, loop_map_title = _get_loop_map(selected_loop_parm, selected_loop_cycle)
current_loop_bias_vec, current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec = \
_get_loops(selected_loop_cycle, selected_loop_pos)
current_w_vec, current_sho_guess, current_sho_fit, current_raw_data = _get_sho(selected_loop_pos,
selected_step,
selected_loop_cycle)
cmap = get_cmap_object(cmap)
'''
Build the figure
'''
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(17, 17))
ax_loop_map = axes.flatten()[0]
ax_loop_pgf = axes.flatten()[1]
ax_sho_amp = axes.flatten()[2]
ax_sho_phase = axes.flatten()[3]
# Plot the map of the loop parameters
plt_loop_map, loop_cbar = plot_map(ax_loop_map, loop_parm_map, cmap=cmap)
loop_vert_line = ax_loop_map.axvline(x=pos_dims[0], color='k')
loop_horz_line = ax_loop_map.axhline(y=pos_dims[1], color='k')
ax_loop_map.set_title(loop_map_title)
# Plot the Loops
plt_loop_proj = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_proj_vec, 'k', label='Loop Projection')
plt_loop_guess = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_guess_vec, 'g', label='Loop Guess')
plt_loop_fit = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_fit_vec, 'r--', label='Loop Fit')
ax_loop_pgf.legend()
# Plot the amplitude of the SHO Guess, SHO Fit, and Raw Data
plt_raw_data_amp = ax_sho_amp.plot(current_w_vec, np.abs(current_raw_data), 'k', label='Raw Data')
plt_sho_guess_amp = ax_sho_amp.plot(current_w_vec, np.abs(current_sho_guess), 'g', label='SHO Guess')
plt_sho_fit_amp = ax_sho_amp.plot(current_w_vec, np.abs(current_sho_fit), 'r--', label='SHO Fit')
ax_sho_amp.legend()
# Plot the phase of the SHO Guess, SHO Fit, and Raw Data
plt_raw_data_phase = ax_sho_phase.plot(current_w_vec, np.angle(current_raw_data), 'k', label='Raw Data')
plt_sho_guess_phase = ax_sho_phase.plot(current_w_vec, np.angle(current_sho_guess), 'g', label='SHO Guess')
plt_sho_fit_phase = ax_sho_phase.plot(current_w_vec, np.angle(current_sho_fit), 'r--', label='SHO Fit')
ax_sho_phase.legend()
fig.tight_layout()
def _update_loop_map(parameter_name, selected_cycle):
loop_parm_map, loop_map_title = _get_loop_map(parameter_name, selected_cycle)
plt_loop_map.set_data(loop_parm_map)
ax_loop_map.set_title(loop_map_title)
def _update_crosshairs(x_pos, y_pos):
loop_vert_line.set_xdata(x_pos)
loop_horz_line.set_ydata(y_pos)
def _update_loop_plots(selected_loop_cycle, x_pos, y_pos):
current_loop_bias_vec, current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec = \
_get_loops(selected_loop_cycle, [x_pos, y_pos])
# Update the bias vectors
plt_loop_proj.set_xdata(current_loop_bias_vec)
plt_loop_guess.set_xdata(current_loop_bias_vec)
plt_loop_fit.set_xdata(current_loop_bias_vec)
# Update the ploted data
plt_loop_proj.set_xdata(current_loop_proj_vec)
plt_loop_guess.set_xdata(current_loop_guess_vec)
plt_loop_fit.set_xdata(current_loop_fit_vec)
def _update_sho_plots(selected_loop_cycle, x_pos, y_pos, selected_step):
current_w_vec, current_sho_guess, current_sho_fit, current_raw_data = _get_sho([x_pos, y_pos],
selected_step,
selected_loop_cycle)
# Update x-date with new w_vec
plt_raw_data_amp.set_xdata(current_w_vec)
plt_raw_data_phase.set_xdata(current_w_vec)
plt_sho_guess_amp.set_xdata(current_w_vec)
plt_sho_guess_phase.set_xdata(current_w_vec)
plt_sho_fit_amp.set_xdata(current_w_vec)
plt_sho_fit_phase.set_xdata(current_w_vec)
# Update the y-data
plt_raw_data_amp.set_ydata(np.amp(current_raw_data))
plt_raw_data_phase.set_ydata(np.angle(current_raw_data))
plt_sho_guess_amp.set_ydata(np.amp(current_sho_guess))
plt_sho_guess_phase.set_ydata(np.angle(current_sho_guess))
plt_sho_fit_amp.set_ydata(np.amp(current_sho_fit))
plt_sho_fit_phase.set_ydata(np.angle(current_sho_fit))
fig_filename, _ = os.path.splitext(h5_loop_parameters.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
display(fig)
x_pos_widget = widgets.FloatSlider(min=0.0, max=float(pos_dims[0]), step=pos_dims[0] / 100,
value=selected_loop_pos[0])
y_pos_widget = widgets.FloatSlider(min=0.0, max=float(pos_dims[1]), step=pos_dims[1] / 100,
value=selected_loop_pos[1])
loop_cycle_widget = widgets.IntSlider(min=0, max=loop_num_cycles, step=1, value=selected_loop_cycle)
spec_step_widget = widgets.IntSlider(min=0, max=steps_per_loop, step=1, value=selected_step)
widgets.interact(_update_loop_map,
parameter_name=list(loop_parameter_names),
selected_cycle=loop_cycle_widget)
widgets.interact(_update_crosshairs,
x_pos=x_pos_widget, y_pos=y_pos_widget)
widgets.interact(_update_loop_plots,
selected_loop_cycle=loop_cycle_widget,
x_pos=x_pos_widget, y_pos=y_pos_widget)
widgets.interact(_update_sho_plots,
selected_loop_cycle=loop_cycle_widget,
x_pos=x_pos_widget, y_pos=y_pos_widget,
selected_step=spec_step_widget)
return fig
[docs]
def plot_loop_sho_raw_comparison(h5_loop_parameters, h5_sho_grp, h5_raw_dset,
selected_loop_parm=None,
selected_loop_cycle=0,
selected_loop_pos=[0, 0],
selected_step=0, tick_font_size=14,
cmap='viridis',
step_chan='DC_Offset'):
"""
Parameters
----------
h5_loop_parameters : h5py.Dataset
Dataset containing the loop parameters
h5_sho_grp : h5py.Group
Group containing the SHO fitting results, based on which the loop fit
was performed
h5_raw_dset : h5py.Dataset
Dataset containing the raw BE measurement, that was used to get
h5_sho_grp
selected_loop_parm : str
The initial loop parameter to be plotted
selected_loop_cycle : int
The initial loop cycle to be plotted
selected_loop_pos : array-like of two ints
The initial position to be plotted
selected_step : int
The initial bias step to be plotted
tick_font_size : int
Font size for the axes tick labels
cmap : str or matplotlib.colors.Colormap
Colormap to be used in plotting the parameter map
step_chan : str
Name of spectral dimension loops were fit over
Returns
-------
None
"""
if not isinstance(h5_loop_parameters, USIDataset):
h5_loop_parameters = USIDataset(h5_loop_parameters)
# Find the precursor datasets used to calculate these parameters
h5_loop_grp = h5_loop_parameters.parent
h5_loop_projections = USIDataset(h5_loop_grp['Projected_Loops'], sort_dims=False)
h5_loop_fit = USIDataset(h5_loop_grp['Fit'], sort_dims=False)
h5_loop_guess = USIDataset(h5_loop_grp['Guess'], sort_dims=False)
h5_sho_fit = USIDataset(h5_sho_grp['Fit'], sort_dims=False)
h5_sho_guess = USIDataset(h5_sho_grp['Guess'], sort_dims=False)
h5_main = h5_raw_dset
# h5_main.toggle_sorting()
# Now get the needed ancillary datasets for each main dataset
pos_dims = h5_loop_parameters.pos_dim_sizes
pos_labs = h5_loop_parameters.pos_dim_labels
# h5_loop_spec_inds = h5_loop_parameters.h5_spec_inds
h5_loop_spec_vals = h5_loop_parameters.h5_spec_vals
# loop_spec_order = get_sort_order(h5_loop_spec_inds)
loop_spec_dims = h5_loop_parameters.spec_dim_sizes
loop_spec_labs = h5_loop_parameters.spec_dim_labels
h5_sho_spec_inds = h5_sho_fit.h5_spec_inds
h5_sho_spec_vals = h5_sho_fit.h5_spec_vals
# sho_spec_order = get_sort_order(h5_sho_spec_inds)
sho_spec_dims = h5_sho_fit.spec_dim_sizes
sho_spec_labs = h5_sho_fit.spec_dim_labels
h5_main_spec_inds = h5_main.h5_spec_inds
h5_main_spec_vals = h5_main.h5_spec_vals
# main_spec_order = get_sort_order(h5_main_spec_inds)
main_spec_dims = h5_main.spec_dim_sizes
main_spec_labs = h5_main.spec_dim_labels
'''
Select the initial plotting slices
'''
loop_parameter_names = h5_loop_parameters.dtype.names
loop_num_cycles = h5_loop_parameters.shape[1]
# loop_parameter_spec_labs = h5_loop_parameters.spec_dim_labels
sho_bias_dim = sho_spec_labs.index(step_chan)
steps_per_loop = sho_spec_dims[sho_bias_dim]
main_bias_dim = main_spec_labs.index(step_chan)
main_freq_dim = main_spec_labs.index('Frequency')
if selected_loop_parm is None:
selected_loop_parm = loop_parameter_names[0]
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
'''
Get the bias vector to be plotted against
'''
loop_bias_vec = h5_sho_spec_vals[get_attr(h5_sho_spec_vals, step_chan)].squeeze()
shift_ind = int(-1 * steps_per_loop / 4)
loop_bias_vec = loop_bias_vec.reshape(sho_spec_dims[::-1])
loop_bias_vec = np.moveaxis(loop_bias_vec, len(loop_bias_vec.shape) - sho_bias_dim - 1, 0)
loop_bias_vec = np.reshape(loop_bias_vec, [sho_spec_dims[sho_bias_dim], -1])
loop_bias_vec = np.roll(loop_bias_vec.reshape(steps_per_loop, -1), shift_ind, axis=0)
'''
Get the frequency vector to be plotted against
'''
full_w_vec = h5_main_spec_vals[h5_main_spec_vals.attrs['Frequency']]
full_w_vec, _ = reshape_to_n_dims(full_w_vec, h5_spec=h5_main_spec_inds)
full_w_vec = full_w_vec.squeeze()
'''
Define functions to get the data
'''
def _get_loop_map(selected_loop_parm, selected_loop_cycle):
# Build the map of the chosen loop parameter
loop_parameter_map = np.reshape(h5_loop_parameters[selected_loop_parm, :, selected_loop_cycle],
[pos_dims[0], pos_dims[1]])
# Also create the title string for the map
loop_map_title = list()
for label in loop_spec_labs:
val = h5_loop_spec_vals[get_attr(h5_loop_spec_vals, label)].squeeze()[selected_loop_cycle]
loop_map_title.append('{}: {}'.format(label, val))
loop_map_title = ' - '.join(loop_map_title)
return loop_parameter_map, loop_map_title
def _get_loops(selected_loop_cycle, selected_loop_pos):
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
# Now build the loop plot for the selected position in the loop map
selected_loop_bias_vec = loop_bias_vec[:, selected_loop_cycle]
pos_ind = np.ravel_multi_index(selected_loop_pos, pos_dims)
slice_dict = dict()
for pos_dim, dim_ind in zip(pos_labs, selected_loop_pos):
slice_dict[pos_dim] = dim_ind
for spec_dim, dim_ind in zip(loop_spec_labs, selected_loop_ndims):
slice_dict[spec_dim] = dim_ind
loop_proj_vec, _ = h5_loop_projections.slice(slice_dict, as_scalar=False)
loop_proj_vec2 = np.roll(loop_proj_vec.squeeze(), shift_ind)
loop_guess_slice, _ = h5_loop_guess.slice(slice_dict, as_scalar=True)
loop_fit_slice, _ = h5_loop_fit.slice(slice_dict, as_scalar=True)
loop_guess_vec = loop_fit_function(selected_loop_bias_vec,
loop_guess_slice.squeeze().tolist())
loop_fit_vec = loop_fit_function(selected_loop_bias_vec,
loop_fit_slice.squeeze().tolist())
return selected_loop_bias_vec, loop_proj_vec2, loop_guess_vec, loop_fit_vec
def _get_sho(selected_loop_pos, selected_step, selected_loop_cycle):
selected_loop_ndims = np.unravel_index(selected_loop_cycle, loop_spec_dims, order='F')
# get the SHO Guess and Fit and Raw Data for the selected position, cycle, and step
pos_ind = np.ravel_multi_index(selected_loop_pos, pos_dims)
# Get the slice of the sho guess and fit
sho_slice = {key: int(val) for key, val in zip(pos_labs, selected_loop_pos)}
sho_slice[sho_spec_labs[sho_bias_dim]] = selected_step
for key, val in zip(loop_spec_labs, selected_loop_ndims):
sho_slice[key] = int(val)
# Get the slice of the Raw Data
raw_data_vec = h5_main.slice(sho_slice)[0]
# Get the frequency vector for the selected step
w_vec = np.moveaxis(full_w_vec, main_freq_dim, len(main_spec_dims) - 1) # Move frequency to the end
w_vec2 = np.rollaxis(w_vec, main_bias_dim - 1, 0)[selected_step][selected_loop_ndims]
sho_guess = h5_sho_guess.slice(sho_slice)[0].tolist()
sho_guess = SHOfunc(sho_guess, w_vec2)
sho_fit = h5_sho_fit.slice(sho_slice)[0].tolist()
sho_fit = SHOfunc(sho_fit, w_vec2)
return w_vec2, sho_guess, sho_fit, raw_data_vec
'''
Get the starting values
'''
loop_parm_map, loop_map_title = _get_loop_map(selected_loop_parm, selected_loop_cycle)
current_loop_bias_vec, current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec = \
_get_loops(selected_loop_cycle, selected_loop_pos)
current_w_vec, current_sho_guess, current_sho_fit, current_raw_data = _get_sho(selected_loop_pos,
selected_step,
selected_loop_cycle)
'''
Build the figure
'''
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(17, 17))
ax_loop_map = axes.flatten()[0]
ax_loop_pgf = axes.flatten()[1]
ax_sho_amp = axes.flatten()[2]
ax_sho_phase = axes.flatten()[3]
# Plot the map of the loop parameters
loop_map, loop_map_cbar = plot_map(ax_loop_map, loop_parm_map)
crosshair = ax_loop_map.plot(selected_loop_pos[0], selected_loop_pos[1], 'k+')[0]
ax_loop_map.set_title(loop_map_title)
ax_loop_map.set_xlabel('X Position')
ax_loop_map.set_ylabel('Y Position')
# Plot the Loops
loop_proj_plot = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_proj_vec, 'k', label='Loop Projection')[0]
loop_guess_plot = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_guess_vec, 'g', label='Loop Guess')[0]
loop_fit_plot = ax_loop_pgf.plot(current_loop_bias_vec, current_loop_fit_vec, 'r--', label='Loop Fit')[0]
ax_loop_pgf.legend()
loop_pgf_title = ' - '.join(['Position: ({}, {})'.format(selected_loop_pos[0], selected_loop_pos[1]),
loop_map_title])
ax_loop_pgf.set_title(loop_pgf_title)
ax_loop_pgf.set_ylabel('PR (a.u.)')
ax_loop_pgf.set_xlabel('V_DC (V)')
ax_loop_pgf.axis('tight')
# Plot the amplitude of the SHO Guess, SHO Fit, and Raw Data
raw_amp_plot = ax_sho_amp.plot(current_w_vec, np.abs(current_raw_data), 'k*', label='Raw Data Amplitude')[0]
guess_amp_plot = ax_sho_amp.plot(current_w_vec, np.abs(current_sho_guess), 'g', label='SHO Guess Amplitude')[0]
fit_amp_plot = ax_sho_amp.plot(current_w_vec, np.abs(current_sho_fit), 'r:', label='SHO Fit Amplitude')[0]
ax_sho_amp.legend()
sho_title = ' - '.join(['Bias Step: {}'.format(selected_step), loop_pgf_title])
ax_sho_amp.set_title(sho_title)
ax_sho_amp.set_ylabel('Amplitude (V)')
ax_sho_amp.set_xlabel('Frequency (Hz)')
ax_sho_amp.axis('tight')
# Plot the phase of the SHO Guess, SHO Fit, and Raw Data
raw_phase_plot = ax_sho_phase.plot(current_w_vec, np.angle(current_raw_data), 'k*', label='Raw Data Phase')[0]
guess_phase_plot = ax_sho_phase.plot(current_w_vec, np.angle(current_sho_guess), 'g', label='SHO Guess Phase')[0]
fit_phase_plot = ax_sho_phase.plot(current_w_vec, np.angle(current_sho_fit), 'r:', label='SHO Fit Phase')[0]
ax_sho_phase.legend()
ax_sho_phase.set_title(sho_title)
ax_sho_phase.set_ylabel('Amplitude (V)')
ax_sho_phase.set_xlabel('Frequency (Hz)')
ax_sho_phase.axis('tight')
for axis in [ax_loop_pgf, ax_sho_amp, ax_sho_phase]:
set_tick_font_size(axis, tick_font_size)
axis.ticklabel_format(axis='both', style='sci', scilimits=(-2, 2))
plt.show()
# Make some widgets now so we can reference them in updates
loop_parm_widget = widgets.Dropdown(options=loop_parameter_names, value=selected_loop_parm)
loop_cycle_widget = widgets.IntSlider(min=0, max=loop_num_cycles - 1, step=1, value=selected_loop_cycle)
spec_step_widget = widgets.IntSlider(min=0, max=steps_per_loop - 1, step=1, value=selected_step)
def _update_loop_plots(selected_loop_cycle, xdata, ydata):
# Get new data
current_loop_bias_vec, current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec = \
_get_loops(selected_loop_cycle, (xdata, ydata))
# Update loop plots
loop_proj_plot.set_xdata(current_loop_bias_vec)
loop_proj_plot.set_ydata(current_loop_proj_vec)
loop_guess_plot.set_xdata(current_loop_bias_vec)
loop_guess_plot.set_ydata(current_loop_guess_vec)
loop_fit_plot.set_xdata(current_loop_bias_vec)
loop_fit_plot.set_ydata(current_loop_fit_vec)
loop_map_title = ax_loop_map.get_title()
loop_pgf_title = ' - '.join(['Position: ({}, {})'.format(xdata, ydata),
loop_map_title])
ax_loop_pgf.set_title(loop_pgf_title)
loop_min = np.min([current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec])
loop_max = np.max([current_loop_proj_vec, current_loop_guess_vec, current_loop_fit_vec])
loop_min *= (1 - np.sign(loop_min) * 0.5)
loop_max *= (1 + np.sign(loop_max) * 0.5)
ax_loop_pgf.set_ylim([loop_min, loop_max])
def _update_sho_plots(selected_loop_cycle, selected_step, xdata, ydata):
# Get the updated data
current_w_vec, current_sho_guess, current_sho_fit, current_raw_data = _get_sho((xdata, ydata),
selected_step,
selected_loop_cycle)
# Update SHO/Raw plots
loop_pgf_title = ax_loop_pgf.get_title()
sho_title = ' - '.join(['Bias Step: {}'.format(selected_step), loop_pgf_title])
raw_amp_plot.set_xdata(current_w_vec)
raw_amp_plot.set_ydata(np.abs(current_raw_data))
guess_amp_plot.set_xdata(current_w_vec)
guess_amp_plot.set_ydata(np.abs(current_sho_guess))
fit_amp_plot.set_xdata(current_w_vec)
fit_amp_plot.set_ydata(np.abs(current_sho_fit))
ax_sho_amp.set_title(sho_title)
ax_sho_amp.set_ylim([np.min(np.abs([current_raw_data, current_sho_guess, current_sho_fit])) * 0.95,
np.max(np.abs([current_raw_data, current_sho_guess, current_sho_fit])) * 1.05])
raw_phase_plot.set_xdata(current_w_vec)
raw_phase_plot.set_ydata(np.angle(current_raw_data))
guess_phase_plot.set_xdata(current_w_vec)
guess_phase_plot.set_ydata(np.angle(current_sho_guess))
fit_phase_plot.set_xdata(current_w_vec)
fit_phase_plot.set_ydata(np.angle(current_sho_fit))
ax_sho_phase.set_title(sho_title)
def pos_picker(event):
# Allow for picking a new position.
if not ax_loop_map.axes.in_axes(event):
return
selected_loop_cycle = loop_cycle_widget.value
selected_step = spec_step_widget.value
xdata = int(round(event.xdata))
ydata = int(round(event.ydata))
current_pos = {pos_labs[0]: xdata, pos_labs[1]: ydata}
pos_dim_vals = list(range(len(pos_labs)))
for pos_dim_ind, pos_dim_name in enumerate(pos_labs):
pos_dim_vals[pos_dim_ind] = current_pos[pos_dim_name]
crosshair.set_xdata(xdata)
crosshair.set_ydata(ydata)
_update_loop_plots(selected_loop_cycle, xdata, ydata)
_update_sho_plots(selected_loop_cycle, selected_step, xdata, ydata)
fig.canvas.draw()
def _update_loop_parm(selected_loop_parm):
loop_parm_map, loop_map_title = _get_loop_map(selected_loop_parm, loop_cycle_widget.value)
loop_map.set_data(loop_parm_map)
loop_map.set_clim(vmin=np.min(loop_parm_map), vmax=np.max(loop_parm_map))
ax_loop_map.set_title(loop_map_title)
fig.canvas.draw()
def _update_loop_cycle(selected_loop_cycle):
selected_step = spec_step_widget.value
xdata, ydata = crosshair.get_xydata().flatten().astype('int')
# Update the loop map
loop_parm_map, loop_map_title = _get_loop_map(loop_parm_widget.value, selected_loop_cycle)
loop_map.set_data(loop_parm_map)
loop_map.set_clim(vmin=np.min(loop_parm_map), vmax=np.max(loop_parm_map))
ax_loop_map.set_title(loop_map_title)
# Update the linet plots
_update_loop_plots(selected_loop_cycle, xdata, ydata)
_update_sho_plots(selected_loop_cycle, selected_step, xdata, ydata)
fig.canvas.draw()
def _update_spec_step(selected_step):
selected_loop_cycle = loop_cycle_widget.value
xdata, ydata = crosshair.get_xydata().flatten().astype('int')
_update_sho_plots(selected_loop_cycle, selected_step, xdata, ydata)
fig.canvas.draw()
cid = loop_map.figure.canvas.mpl_connect('button_press_event', pos_picker)
fig_filename, _ = os.path.splitext(h5_loop_projections.file.filename)
display(save_fig_filebox_button(fig, fig_filename + '.png'))
widgets.interact(_update_loop_parm, selected_loop_parm=loop_parm_widget)
widgets.interact(_update_loop_cycle, selected_loop_cycle=loop_cycle_widget)
widgets.interact(_update_spec_step, selected_step=spec_step_widget)
return fig
def _add_loop_parameters(axes, switching_coef_vec):
"""
Add the loop parameters for the given loop to a list of axes
Parameters
----------
axes : list of matplotlib.pyplo.axes
Plot axes to add the coeffients to
switching_coef_vec : 1D numpy.ndarray
Array of loop parameters arranged by position
Returns
-------
axes : list of matplotlib.pyplo.axes
"""
positions = np.linspace(0, switching_coef_vec.shape[0] - 1, len(axes.flat), dtype=np.int)
for ax, pos in zip(axes.flat, positions):
ax.axvline(switching_coef_vec[pos]['V+'], c='k', label='V+')
ax.axvline(switching_coef_vec[pos]['V-'], c='r', label='V-')
ax.axvline(switching_coef_vec[pos]['Nucleation Bias 1'], c='k', ls=':', label='Nucleation Bias 1')
ax.axvline(switching_coef_vec[pos]['Nucleation Bias 2'], c='r', ls=':', label='Nucleation Bias 2')
ax.axhline(switching_coef_vec[pos]['R+'], c='k', ls='-.', label='R+')
ax.axhline(switching_coef_vec[pos]['R-'], c='r', ls='-.', label='R-')
return axes
[docs]
def plot_1d_spectrum(data_vec, freq, title, **kwargs):
"""
Plots the Step averaged BE response
Parameters
------------
data_vec : 1D numpy array
Response of one BE pulse
freq : 1D numpy array
BE frequency that serves as the X axis of the plot
title : String
Plot group name
Returns
---------
fig : Matplotlib.pyplot figure
Figure handle
axes : Matplotlib.pyplot axis
Axis handle
"""
if len(data_vec) != len(freq):
raise ValueError('Incompatible data sizes! spectrum: '
+ str(len(data_vec)) + ', frequency: ' + str(freq.shape))
freq *= 1E-3 # to kHz
title = title + ': mean UDVS, mean spatial response'
fig, axes = plot_complex_spectra(np.expand_dims(data_vec, axis=0), freq, title=title,
subtitle_prefix='', num_comps=1, x_label='Frequency (kHz)',
figsize=(5, 3), amp_units='V', **kwargs)
return fig, axes
[docs]
def plot_2d_spectrogram(mean_spectrogram, freq, title=None, **kwargs):
"""
Plots the position averaged spectrogram
Parameters
------------
mean_spectrogram : 2D numpy complex array
Means spectrogram arranged as [frequency, UDVS step]
freq : 1D numpy float array
BE frequency that serves as the X axes of the plot
title : str, optional
Plot group name
Returns
---------
fig : Matplotlib.pyplot figure
Figure handle
axes : Matplotlib.pyplot axes
Axis handle
"""
if mean_spectrogram.shape[1] != freq.size:
if mean_spectrogram.shape[0] == freq.size:
mean_spectrogram = mean_spectrogram.T
else:
raise ValueError('plot_2d_spectrogram: Incompatible data sizes!!!! spectrogram: '
+ str(mean_spectrogram.shape) + ', frequency: ' + str(freq.shape))
fig, axes = plot_complex_spectra(np.expand_dims(mean_spectrogram, axis=0), num_comps=1, title=title,
x_label='Frequency (kHz)', y_label='UDVS step', subtitle_prefix='',
figsize=(5, 3), origin='lower', stdevs=None, amp_units='V', **kwargs)
# Changing the X axis labels
x_ticks = np.linspace(0, mean_spectrogram.shape[1] - 1, 5, dtype=int)
x_tick_labs = [str(np.round(freq[ind], 2)) for ind in x_ticks]
for axis in axes:
axis.set_xticks(x_ticks)
axis.set_xticklabels(x_tick_labs)
return fig, axes
[docs]
def plot_histograms(p_hist, p_hbins, title, figure_path=None):
"""
Plots the position averaged spectrogram
Parameters
------------
p_hist : 2D numpy array
histogram data arranged as [physical quantity, frequency bin]
p_hbins : 1D numpy array
BE frequency that serves as the X axis of the plot
title : String
Plot group name
figure_path : String / Unicode
Absolute path of the file to write the figure to
Returns
---------
fig : Matplotlib.pyplot figure
Figure handle
"""
base_fig_size = 7
h_fig = base_fig_size
w_fig = base_fig_size * 4
fig = plt.figure(figsize=(w_fig, h_fig))
fig.suptitle(title)
iplot = 0
p_Nx, p_Ny = np.amax(p_hbins, axis=1) + 1
p_hist = np.reshape(p_hist, (4, p_Ny, p_Nx))
iplot += 1
p_plot_title = 'Spectral BEHistogram Amp (log10 of counts)'
p_plot = fig.add_subplot(1, 4, iplot, title=p_plot_title)
p_im = p_plot.imshow(np.rot90(np.log10(p_hist[0])), interpolation='nearest')
p_plot.axis('tight')
fig.colorbar(p_im, fraction=0.1)
iplot += 1
p_plot_title = 'Spectral BEHistogram Phase (log10 of counts)'
p_plot = fig.add_subplot(1, 4, iplot, title=p_plot_title)
p_im = p_plot.imshow(np.rot90(np.log10(p_hist[1])), interpolation='nearest')
p_plot.axis('tight')
fig.colorbar(p_im, fraction=0.1)
iplot += 1
p_plot_title = 'Spectral BEHistogram Real (log10 of counts)'
p_plot = fig.add_subplot(1, 4, iplot, title=p_plot_title)
p_im = p_plot.imshow(np.rot90(np.log10(p_hist[2])), interpolation='nearest')
p_plot.axis('tight')
fig.colorbar(p_im, fraction=0.1)
iplot += 1
p_plot_title = 'Spectral BEHistogram Imag (log10 of counts)'
p_plot = fig.add_subplot(1, 4, iplot, title=p_plot_title)
p_im = p_plot.imshow(np.rot90(np.log10(p_hist[3])), interpolation='nearest')
p_plot.axis('tight')
fig.colorbar(p_im, fraction=0.1)
if figure_path:
plt.savefig(figure_path, format='png')
return fig
[docs]
def show(img, cmap = 'plasma', colorbar = True):
"""Displays image with colorbar."""
imgstd = img.std()
imgmean = img.mean()
ll = imgmean - (2*imgstd)
ul = imgmean + (2*imgstd)
# for i in range(img.shape[0]):
# for j in range(img.shape[1]):
# if np.logical_or((img[i, j] < ll), (img[i, j] > ul)):
# img[i, j] = imgmean
# img = np.array(img)
fig = plt.imshow(img, cmap=cmap)
plt.clim(ll,ul)
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
if colorbar == True:
plt.colorbar()
return
[docs]
def SHOfunc(parms, w_vec):
"""
Generates the SHO response over the given frequency band
Parameters
-----------
parms : list or tuple
SHO parae=(A,w0,Q,phi)
w_vec : 1D numpy array
Vector of frequency values
"""
return parms[0] * np.exp(1j * parms[3]) * parms[1] ** 2 / \
(w_vec ** 2 - 1j * w_vec * parms[1] / parms[2] - parms[1] ** 2)
[docs]
def viz_berelaxfit(berelaxfit, bias_ind =0, t_time=0 , x_col=0, h_row=0, sensitivity=1, phase_offset=0,
starts_with="write", fit_method='Exponential'):
"""
:param berelaxfit: dataset from berelaxfit fit process class
:param bias_ind: bias step within relaxation measurement, integer
:param t_time: time step within relaxation measurement, integer
:param x_col: display relaxation spectrum at this x index
:param h_row: display relaxation spectrum at this y index
:param sensitivity: tip sensitivity for converting signal to pm
:param phase_offset: phase offset for measurement
:param starts_with: 'write' or 'read' step
:param fit_method: can be 'Exponential' 'Double_Exp' or 'Logistic'
:return: along with widgets will produce an interactive graphic to explore data; see jupyter notebook for example
shows raw PFM data along with fit, bias as function of time, SHO fitted phase + amplitude,
Raw phase + amplitude, and fitted time constant and amplitude.
"""
# experimental parameters needed for visualization
fit_method = fit_method
raw_data = USIDataset(berelaxfit.parent.parent.parent['Raw_Data'])
no_freq = raw_data.spec_dim_sizes[0]
# freq_vals = raw_data.get_spec_values('Frequency')
#seems there is a bug in the acquisition software; should not
#need to specify no_freq below when printing raw data,
#the size of the frequency dimension is 49, but when calling
#the freqeuncy values, a list of len 17k is provided
freq_vals = raw_data.h5_spec_vals[0,:no_freq]
raw_data_pos_sizes = raw_data.pos_dim_sizes
x_length = raw_data_pos_sizes[0]
y_length = raw_data_pos_sizes[1]
raw_phase = np.angle(raw_data[:, :])
raw_amp = abs(raw_data[:, :])
sho_fit = USIDataset(berelaxfit.parent.parent['Fit'])
sho_phase = sho_fit['Phase [rad]'].reshape(x_length, y_length, -1)
sho_amplitude = sho_fit['Amplitude [V]'].reshape(x_length, y_length, -1)
sho_frequency = sho_fit['Frequency [Hz]'].reshape(x_length, y_length, -1)
sho_quality_factor = sho_fit['Quality Factor'].reshape(x_length, y_length, -1)
mixed_signal = sho_fit['Amplitude [V]']*sensitivity* np.cos(sho_fit['Phase [rad]']+phase_offset)
mixed_signal_reshape = mixed_signal.reshape(x_length, y_length, -1)
no_read_steps = berelaxfit.parent.parent.parent.parent.attrs['VS_num_meas_per_read_step']
no_write_steps = berelaxfit.parent.parent.parent.parent.attrs['VS_num_meas_per_write_step']
time_elapsed_per_step = berelaxfit.parent.parent.parent.parent.attrs['BE_pulse_duration_[s]']
tot_time_elapsed_read = (no_read_steps) * time_elapsed_per_step
time_axis = np.arange(0, tot_time_elapsed_read, step=time_elapsed_per_step)
all_dc_offset_values = sho_fit.h5_spec_vals[1, np.argwhere(sho_fit.h5_spec_inds[0] == 0)]
# no of rs spectra is the number of times pulse repeats. 0 = start of new pulse
no_rs_spectra = int(len(np.argwhere(sho_fit.h5_spec_inds[0, :] == 0))/2)
total_time_steps = no_read_steps + no_write_steps
dc_offset_nonzero = np.nonzero(all_dc_offset_values)[0]
dc_offset_expand = sho_fit.h5_spec_vals[1, :]
all_inds_split = np.array_split(np.arange(0, len(dc_offset_expand), step=1), no_rs_spectra)
read_inds_split = []
if starts_with == 'write':
for i in range(no_rs_spectra):
read_inds_split.append(all_inds_split[i][no_write_steps:])
#write_dc_offset_values = [sho_fit.h5_spec_vals[1, np.argwhere(sho_fit.h5_spec_vals[0] == 0)]]
write_dc_offset_values = all_dc_offset_values[::2]
if type(write_dc_offset_values) == np.float32:
write_dc_offset_values = [write_dc_offset_values]
if starts_with == 'read':
for i in range(no_rs_spectra):
read_inds_split.append(all_inds_split[i][:-int(no_write_steps)])
write_dc_offset_values = sho_fit.h5_spec_vals[1, np.argwhere(sho_fit.h5_spec_vals[0] == no_read_steps)]
if type(write_dc_offset_values) == np.float32:
write_dc_offset_values = [write_dc_offset_values]
raw_phase_reshape = raw_phase.reshape((x_length, y_length, total_time_steps, no_freq))
raw_amp_reshape = raw_amp.reshape((x_length,y_length, total_time_steps, no_freq))
if fit_method == 'Exponential':
amp_fit_reshape = berelaxfit['Amplitude [pm]'].reshape(x_length, y_length, -1)
tau_fit_reshape = berelaxfit['Time_Constant [s]'].reshape(x_length, y_length, -1)
offset_fit_reshape = berelaxfit['Offset [pm]'].reshape(x_length, y_length, -1)
if fit_method == 'Double_Exp':
amp1_fit_reshape = berelaxfit['Amplitude [pm]'].reshape(x_length, y_length, -1)
tau1_fit_reshape = berelaxfit['Time_Constant [s]'].reshape(x_length, y_length, -1)
amp2_fit_reshape = berelaxfit['Amplitude 2 [pm]'].reshape(x_length, y_length, -1)
tau2_fit_reshape = berelaxfit['Time_Constant 2 [s]'].reshape(x_length, y_length, -1)
offset_fit_reshape = berelaxfit['Offset [pm]'].reshape(x_length, y_length, -1)
if fit_method == 'Str_Exp':
amp_fit_reshape = berelaxfit['Amplitude [pm]'].reshape(x_length, y_length, -1)
beta_fit_reshape = berelaxfit['Beta'].reshape(x_length, y_length, -1)
offset_fit_reshape = berelaxfit['Offset [pm]'].reshape(x_length, y_length, -1)
if fit_method == 'Logistic':
A_reshape = berelaxfit['A'].reshape(x_length, y_length, -1)
K_reshape = berelaxfit['K'].reshape(x_length, y_length, -1)
B_reshape = berelaxfit['B'].reshape(x_length, y_length, -1)
v_reshape = berelaxfit['v'].reshape(x_length, y_length, -1)
Q_reshape = berelaxfit['Q'].reshape(x_length, y_length, -1)
C_reshape = berelaxfit['C'].reshape(x_length, y_length, -1)
#first plot shared plotting calls
font = {'family': 'DejaVu Sans',
'weight': 'bold',
'size': 18}
plt.rc('font', **font)
plt.figure(1, figsize=(18, 12))
plt.subplot(421)
# if time index IN values of bias key
if t_time in read_inds_split[bias_ind]:
print('Time slice {} is in specified RS spectrum.'.format(t_time), 'Time was unchanged')
plt.plot(time_axis,
mixed_signal_reshape[x_col, h_row, read_inds_split[bias_ind]],
'ro')
# if time index NOT IN values of bias key
if t_time not in read_inds_split[bias_ind]:
print('time slice {} was not in specified RS spectrum'.format(t_time))
t_time = read_inds_split[bias_ind][0]
print('changed time slice to {}'.format(t_time))
plt.plot(time_axis,
mixed_signal_reshape[x_col, h_row, read_inds_split[bias_ind]],
'ro')
plt.title('Response at ({},{}) after {} V'.format(x_col, h_row, write_dc_offset_values[bias_ind]))
plt.xlabel('Time Elapsed (s)')
plt.ylabel('Response (pm)')
# regardless of fit, parameter extraction and sho curve calc should be same
params = (sho_amplitude[x_col, h_row, t_time], sho_frequency[x_col, h_row, t_time],
sho_quality_factor[x_col, h_row, t_time], sho_phase[x_col, h_row, t_time])
sho_curve = np.array(SHOfunc(params, freq_vals))
if fit_method == 'Exponential':
from ..analysis.be_relax_fit import exp
a = amp_fit_reshape[x_col, h_row, bias_ind]
t = tau_fit_reshape[x_col, h_row, bias_ind]
c = offset_fit_reshape[x_col, h_row, bias_ind]
plt.plot(time_axis, exp(time_axis, a, t, c))
plt.subplot(427)
plt.title('Fitted Time Constant ({} V)'.format(write_dc_offset_values[bias_ind]))
tau_fit = tau_fit_reshape[:, :, bias_ind]
tau_fitstd = tau_fit.std()
tau_fitmean = tau_fit.mean()
ll = tau_fitmean - (2 * tau_fitstd)
ul = tau_fitmean + (2 * tau_fitstd)
for i in range(tau_fit.shape[0]):
for j in range(tau_fit.shape[1]):
if np.logical_or((tau_fit[i, j] < ll), (tau_fit[i, j] > ul)):
tau_fit[i, j] = np.nan
tau_fit = np.array(tau_fit)
show(tau_fit)
plt.subplot(428)
plt.title('SHO Phase at time step {}'.format(t_time))
show(sho_fit['Phase [rad]'].reshape(x_length, y_length, -1)[:, :, t_time])
plt.axvline(x=x_col, color='k')
plt.axhline(y=h_row, color='k')
if fit_method == 'Double_Exp':
from ..analysis.be_relax_fit import double_exp
amp1 = amp1_fit_reshape[x_col, h_row, bias_ind]
tau1 = tau1_fit_reshape[x_col, h_row, bias_ind]
amp2 = amp2_fit_reshape[x_col, h_row, bias_ind]
tau2 = tau2_fit_reshape[x_col, h_row, bias_ind]
c = offset_fit_reshape[x_col, h_row, bias_ind]
plt.plot(time_axis, double_exp(time_axis, amp1, tau1, amp2, tau2, c))
plt.subplot(427)
plt.title('A Fitted Time Constant ({} V)'.format(write_dc_offset_values[bias_ind]))
tau2_fit = tau2_fit_reshape[:, :, bias_ind]
tau2_fitstd = tau2_fit.std()
tau2_fitmean = tau2_fit.mean()
ll = tau2_fitmean - (2 * tau2_fitstd)
ul = tau2_fitmean + (2 * tau2_fitstd)
for i in range(tau2_fit.shape[0]):
for j in range(tau2_fit.shape[1]):
if np.logical_or((tau2_fit[i, j] < ll), (tau2_fit[i, j] > ul)):
tau2_fit[i, j] = np.nan
tau2_fit = np.array(tau2_fit)
show(tau2_fit)
plt.subplot(428)
plt.title('Amplitude at ({} V)'.format(write_dc_offset_values[bias_ind]))
amp1_fit = amp1_fit_reshape[:, :, bias_ind]
amp1_fitstd = amp1_fit.std()
amp1_fitmean = amp1_fit.mean()
ll = amp1_fitmean - (2 * amp1_fitstd)
ul = amp1_fitmean + (2 * amp1_fitstd)
for i in range(amp1_fit.shape[0]):
for j in range(amp1_fit.shape[1]):
if np.logical_or((amp1_fit[i, j] < ll), (amp1_fit[i, j] > ul)):
amp1_fit[i, j] = np.nan
amp1_fit = np.array(amp1_fit)
show(amp1_fit)
# show(amp1_fit_reshape[:, :, bias_ind])
plt.axvline(x=x_col, color='k')
plt.axhline(y=h_row, color='k')
if fit_method == 'Str_Exp':
from ..analysis.be_relax_fit import str_exp
amp = amp_fit_reshape[x_col, h_row, bias_ind]
beta = beta_fit_reshape[x_col, h_row, bias_ind]
offset = offset_fit_reshape[x_col, h_row, bias_ind]
plt.plot(time_axis, str_exp(time_axis, amp, beta, offset))
plt.subplot(427)
plt.title('Beta ({} V)'.format(write_dc_offset_values[bias_ind]))
beta_fit = beta_fit_reshape[:, :, bias_ind]
beta_fitstd = beta_fit.std()
beta_fitmean = beta_fit.mean()
ll = beta_fitmean - (2 * beta_fitstd)
ul = beta_fitmean + (2 * beta_fitstd)
for i in range(beta_fit.shape[0]):
for j in range(beta_fit.shape[1]):
if np.logical_or((beta_fit[i, j] < ll), (beta_fit[i, j] > ul)):
beta_fit[i, j] = np.nan
beta_fit = np.array(beta_fit)
show(beta_fit)
plt.subplot(428)
plt.title('Amplitude at ({} V)'.format(write_dc_offset_values[bias_ind]))
amp_fit = amp_fit_reshape[:, :, bias_ind]
amp_fitstd = amp_fit.std()
amp_fitmean = amp_fit.mean()
ll = amp_fitmean - (2 * amp_fitstd)
ul = amp_fitmean + (2 * amp_fitstd)
for i in range(amp_fit.shape[0]):
for j in range(amp_fit.shape[1]):
if np.logical_or((amp_fit[i, j] < ll), (amp_fit[i, j] > ul)):
amp_fit[i, j] = np.nan
amp_fit = np.array(amp_fit)
show(amp_fit)
plt.axvline(x=x_col, color='k')
plt.axhline(y=h_row, color='k')
if fit_method == 'Logistic':
from ..analysis.be_relax_fit import sigmoid
A = A_reshape[x_col, h_row, bias_ind]
K = K_reshape[x_col, h_row, bias_ind]
B = B_reshape[x_col, h_row, bias_ind]
v = v_reshape[x_col, h_row, bias_ind]
Q = Q_reshape[x_col, h_row, bias_ind]
C = C_reshape[x_col, h_row, bias_ind]
plt.plot(time_axis, sigmoid(time_axis, A, K, B, v, Q, C))
plt.subplot(422)
plt.title('Time Steps & Bias for Response Curve')
plt.plot(dc_offset_expand, 'o')
plt.axvspan(xmin=read_inds_split[bias_ind].min(), xmax=read_inds_split[bias_ind].max() + 1, alpha=0.1)
plt.xlabel('Time Step (a.u.)')
plt.ylabel('Bias (V)')
plt.subplot(423)
plt.title('SHO Fitted Phase ({} V)'.format(
write_dc_offset_values[bias_ind])) # after applying {} V'.format(write_dc_offset_values[bias_ind]))
plt.plot(time_axis, sho_fit['Phase [rad]'].reshape(x_length, y_length, -1)[x_col, h_row,
read_inds_split[bias_ind]], 'ro')
plt.xlabel('Time Elapsed (s)')
plt.subplot(424)
plt.title('Raw Phase')
plt.title('Raw Phase at time step{}'.format(t_time))
plt.plot(freq_vals, raw_phase_reshape[x_col, h_row, t_time, :], 'ro')
plt.plot(freq_vals, np.angle(sho_curve), 'g-')
plt.xlabel('Frequency')
if fit_method == 'Exponential' or 'Double_Exp' or 'Str_Exp':
plt.subplot(425)
plt.title('SHO Fitted AMPLITUDE ({} V)'.format(
write_dc_offset_values[bias_ind])) # after applying {} V'.format(write_dc_offset_values[bias_ind]))
plt.plot(time_axis, sho_fit['Amplitude [V]'].reshape(x_length, y_length, -1)[x_col, h_row,
read_inds_split[bias_ind]], 'go')
plt.axvline(x=t_time * time_elapsed_per_step, color='orange')
plt.xlabel('Time Elapsed (s)')
plt.subplot(426)
plt.title('Raw Amp at time step {}'.format(t_time))
plt.plot(freq_vals, raw_amp_reshape[x_col, h_row, t_time, :], 'go')
plt.plot(freq_vals, np.abs(sho_curve), 'b-')
plt.xlabel('Frequency')
plt.tight_layout()
plt.show()