input_table so that string variables are changed as cellstr and multicolumn variables (e.g., scientaEkinRange_eV) are splitted into independent variables. 2) we now support when there is no dataset columns (arrays) by creating a dummy dataset called DS_EMPTY. This is required to create a new h5 file for the first time using h5create.
156 lines
5.8 KiB
Matlab
156 lines
5.8 KiB
Matlab
function success = save_table_as_hdf5(input_table, filename)
|
|
|
|
% This function takes input_table (of table type), structured with
|
|
% Thorsten's FileTable format, and stores it as .h5 file with name
|
|
% filename. Each row is treated as a group, where columns can be attributes
|
|
% of the group or datasets inside the group.
|
|
|
|
% Last update: 11.08.2023
|
|
% By: Juan F. Florez Ospina
|
|
% Email: juan.florez-ospina@psi.ch
|
|
|
|
if istable(input_table)
|
|
|
|
string_columns = input_table(:,vartype("string")).Properties.VariableNames;
|
|
input_table = convertvars(input_table,string_columns,'cellstr');
|
|
% split multicolumn variables
|
|
input_table = splitvars(input_table);
|
|
column_names = input_table.Properties.VariableNames;
|
|
else
|
|
success = 0;
|
|
return
|
|
end
|
|
|
|
% Create array with indices of column_names
|
|
column_names_idx = 1 : length(column_names);
|
|
|
|
% Divide input_table into tables with numeric and cellstr variables/columns
|
|
numeric_table = input_table(:,vartype('numeric')); % group attributes of a timestamped measurement
|
|
cellstr_table = input_table(:,vartype('cellstr')); % group datasets of a timestamped measurement
|
|
|
|
% Record columns/vars original index in reference table
|
|
numeric_columns = numeric_table.Properties.VariableNames;
|
|
numeric_columns_idx = argwhere_var_in_varset(numeric_columns,column_names);
|
|
|
|
str_columns = cellstr_table.Properties.VariableNames;
|
|
str_columns_idx = argwhere_var_in_varset(str_columns,column_names);
|
|
|
|
% Based on homogeneous columns/cell arrays, we identify the remaining columns
|
|
% with possibly heterogeneous entries. Ideally, these should store numeric
|
|
% n-dimensional arrays/datasets.
|
|
|
|
rest_columns = {};
|
|
cntr = 1;
|
|
for i = 1 : length(input_table.Properties.VariableNames)
|
|
variable = input_table.Properties.VariableNames{i};
|
|
|
|
is_str = sum(strcmp(variable,str_columns))>0;
|
|
is_num = sum(strcmp(variable,numeric_columns))>0;
|
|
if ~(is_num || is_str)
|
|
rest_columns{cntr} = variable;
|
|
disp(variable)
|
|
cntr = cntr + 1;
|
|
end
|
|
end
|
|
|
|
rest_columns_idx = argwhere_var_in_varset(rest_columns,column_names);
|
|
|
|
% Create an hdf5 file, where rows are seen as measurements/groups with
|
|
% attributes given by numeric and str variables and datasets given by the
|
|
% remaining variables as long as they are numeric n-dimensional arrays.
|
|
|
|
cell_table = input_table(:,rest_columns);
|
|
[rows, cols] = size(input_table);
|
|
|
|
for i = 1 : rows
|
|
group_name = strcat("/MEAS_",string(i),"/");
|
|
if ~isempty(rest_columns)
|
|
for j = 1 : length(rest_columns)
|
|
dataset_name = strcat("DS",string(rest_columns_idx(j)));
|
|
|
|
% Some table entries do not provide direct access to the object
|
|
% of interest, but may contain either {object} or {{object}}.
|
|
% The following loop solves that problem. TODO: is this generic enough?
|
|
|
|
data = cell_table{i,column_names{rest_columns_idx(j)}}{1}; % <=> data = cell_table{i,rest_columns{j}}{1};
|
|
|
|
while iscell(data)
|
|
data = data{1};
|
|
end
|
|
% when there is no data, we still need to provide a valid size
|
|
if ~isempty(data)
|
|
sz = size(data);
|
|
else
|
|
sz = [1,1];
|
|
end
|
|
%%%%
|
|
% Group's dataset: Create dataset of size sz in a certain group
|
|
h5create(filename, strcat(group_name,dataset_name),sz);
|
|
% Dataset's attribute: Add attribute with dataset_name equal to column_name
|
|
attr = "column_name";
|
|
attr_value = column_names{rest_columns_idx(j)}; % <=> rest_columns{j};
|
|
h5writeatt(filename,strcat(group_name,dataset_name),attr,attr_value)
|
|
|
|
%attr = "column_name_idx";
|
|
%attr_value = rest_columns_idx(j); % <=> rest_columns{j};
|
|
%h5writeatt(filename,strcat(group_name,dataset_name),attr,attr_value)
|
|
|
|
% Assign 'data' to the dataset. 'data' has to be of admissible type.
|
|
try
|
|
h5write(filename,strcat(group_name,dataset_name),data)
|
|
catch exception
|
|
disp(exception)
|
|
%h5write(filename,strcat(group_name,dataset_name),cell_table{i,rest_columns{j}})
|
|
end
|
|
end
|
|
else
|
|
dataset_name = "DS_EMPTY";
|
|
sz = [1,1];
|
|
h5create(filename, strcat(group_name,dataset_name),sz);
|
|
end
|
|
|
|
% Group's attribute: Assign group attributes
|
|
for attr_idx = 1 : length(numeric_columns)
|
|
attr = column_names{numeric_columns_idx(attr_idx)};% <=> attr = numeric_columns{attr_idx};
|
|
attr_value = numeric_table{i,attr};
|
|
|
|
column_idx_tag = ['ATTR',num2str(numeric_columns_idx(attr_idx)),'_'];
|
|
h5writeatt(filename,group_name,[column_idx_tag,attr],attr_value)
|
|
|
|
%attr = "column_name_idx";
|
|
%attr_value = numeric_columns_idx(attr_idx); % <=> rest_columns{j};
|
|
|
|
%h5writeatt(filename,group_name,attr,attr_value)
|
|
end
|
|
|
|
for attr_idx = 1 : length(str_columns)
|
|
|
|
attr = column_names{str_columns_idx(attr_idx)}; % <=> attr = str_columns{attr_idx}
|
|
attr_value = cellstr_table{i,attr};
|
|
|
|
column_idx_tag = ['ATTR',num2str(str_columns_idx(attr_idx)),'_'];
|
|
h5writeatt(filename,group_name,[column_idx_tag,attr],attr_value)
|
|
|
|
%attr = "column_name_idx";
|
|
%attr_value = str_columns_idx(attr_idx); % <=> rest_columns{j};
|
|
|
|
%h5writeatt(filename,group_name,attr,attr_value)
|
|
end
|
|
%h5create(filename,"/g2/DS2",[20 Inf],"Chunksize",[5 5]);
|
|
end
|
|
|
|
success = 1;
|
|
|
|
function idx = argwhere_var_in_varset(var,varset)
|
|
ref_idx = 1 : length(varset);
|
|
if iscellstr(var)
|
|
idx = [];
|
|
for i = 1 : length(var)
|
|
logical_idx = strcmp(var{i},varset);
|
|
idx = [idx,ref_idx(logical_idx)];
|
|
end
|
|
else
|
|
logical_idx = strcmp(var,varset);
|
|
idx = ref_idx(logical_idx);
|
|
end
|