Skip to content
Snippets Groups Projects
Commit 20dd523e authored by Lemmer, Jan's avatar Lemmer, Jan
Browse files

Merge branch 'development'

# Conflicts:
#	CHANGELOG.md
parents 96ec4262 fb919d71
No related branches found
No related tags found
1 merge request!62Introduce changes for V1.0 RC 1
Pipeline #654866 passed
Showing
with 443 additions and 189 deletions
...@@ -21,8 +21,16 @@ classdef config < handle ...@@ -21,8 +21,16 @@ classdef config < handle
% reads config data from config file, if an error occurs the % reads config data from config file, if an error occurs the
% wizard is started by the catch block % wizard is started by the catch block
obj.configFileName = configFileName; obj.configFileName = configFileName;
try try %Validity Check
tmp = what("PlotID");
tmp = strrep(tmp.path,'+PlotID','');
defaultConfigPath = fullfile(tmp,obj.configFileName);
if isfile(defaultConfigPath)
txt = fileread(defaultConfigPath);
else %search on path
txt = fileread(obj.configFileName); txt = fileread(obj.configFileName);
end
obj.configData = jsondecode(txt); obj.configData = jsondecode(txt);
assert(checkConfig(obj)); assert(checkConfig(obj));
if isfield(obj.configData,'ExportPath') if isfield(obj.configData,'ExportPath')
...@@ -45,7 +53,7 @@ classdef config < handle ...@@ -45,7 +53,7 @@ classdef config < handle
function outputArg = checkConfig(obj) function outputArg = checkConfig(obj)
%checkConfig validates the config file %checkConfig validates the config file
% 1. Check if mandatory Fields are set % 1. check if mandatory fields are set
check = isfield(obj.configData,obj.mandatoryFields); check = isfield(obj.configData,obj.mandatoryFields);
outputArg = all(check); outputArg = all(check);
......
classdef dataPath < handle
% DATAPATH stores the datapaths to the research data
% usage of a class is neccessary to support variables, argument
% validation and storing variables as tempory files
properties (SetAccess = protected)
DataPaths (1,:) cell % dataPaths
tmpPath % path to TMP files
ID %PlotID
dataFolderName = 'data' %name for the data folder when using centralized
end
methods
function obj = dataPath(inputPaths,ID)
%DATAPATH Construct an instance of this class
% start with argument validation
obj.ID = ID;
%catch non cell inputs in inputPaths
if ~iscell(inputPaths)
inputPaths = {inputPaths}; %Cell array
end
% handle nested cell arrays
while any(cellfun(@iscell,inputPaths)) % while any of the cells contain cells
% concatenate the content of the cells containing cells
% with the ones that don't contain cells
inputPaths = [inputPaths{cellfun(@iscell,inputPaths)} inputPaths(~cellfun(@iscell,inputPaths))];
end
isStruct = false([1,numel(inputPaths)]);
% strings will cause problems, therefore chars are used
for i=1:numel(inputPaths)
if isstring(inputPaths{i})
inputPaths{i} = char(inputPaths{i});
end
% check for Variable inputs
if isstruct(inputPaths{i})
isStruct(i) = true;
elseif ~ischar(inputPaths{i})
obj.throwError();
end
end
obj.DataPaths = inputPaths;
% create temporary file from all Variables
if any(isStruct)
obj.vars2file(isStruct);
end
% final check if all paths are valid
mustBeDataPath(obj);
end
function mustBeDataPath(obj)
if ~isempty(obj.DataPaths)
%checks if input is a valid DataPath object
tf = ~isfile(obj.DataPaths);
if any(tf)
dataPath.throwError();
end
end
end
function cleanTmpFile(obj)
if ~isempty(obj.tmpPath)
delete(obj.tmpPath{:});
end
end
%% non local functions
vars2file(obj,isvar);
end
methods (Static)
function throwError()
%THROWERROR throws an error Dialog for invalid Data
eidType = 'mustBeDataPath:notaValidFilePath';
msgType = 'DataPaths must contain file-path(s) or Variables';
throwAsCaller(MException(eidType,msgType))
end
end %static
end %class
function obj = vars2file(obj,isStruct)
%vars2file creates a temporary file for all variables in inputPaths
% the number of inputPaths is reduced by the number of variables
tmpEnv= getenv('TMP');
tmpDir = fullfile(tmpEnv,'PlotID');
if ~isfolder(tmpDir)
mkdir(tmpDir);
end
obj.tmpPath = fullfile(tmpDir,[obj.ID,'_vars.mat']);
% save each of the structs
for i=1:numel({obj.DataPaths{isStruct}})
struct = obj.DataPaths{isStruct};
if i==1
save(obj.tmpPath,'-struct','struct');
obj.tmpPath = {obj.tmpPath};
else
tmpPath = fullfile(tmpDir,[obj.ID,'_vars',num2str(i),'.mat']);
save(tmpPath,'-struct','struct');
obj.tmpPath{end+1}=tmpPath;
end
end
% remove variable from Datapath
obj.DataPaths(isStruct) = [];
% add tmppath as Datapath
obj.DataPaths = horzcat(obj.DataPaths, obj.tmpPath);
end
...@@ -5,15 +5,15 @@ classdef userDLG ...@@ -5,15 +5,15 @@ classdef userDLG
% This reduces messaging overhead and code length in PlotID.Publish() % This reduces messaging overhead and code length in PlotID.Publish()
properties properties
configError = false configError = false % error state of reading the config
scriptPublished = false scriptPublished = false % error state of publishing the script
rdFilesPublished = false rdFilesPublished = false % error state of publishing the research data
figurePublished = false figurePublished = false % error state of publishing the figure
msg = '' msg = '' % message to the user
end end
properties (SetAccess = protected) properties (SetAccess = protected)
success = false success = false % product of all states
showMessages {mustBeNumericOrLogical} showMessages {mustBeNumericOrLogical}
forcePublish {mustBeNumericOrLogical} forcePublish {mustBeNumericOrLogical}
ID %plotID ID %plotID
......
function Publish(DataPaths,scriptPath, figure, options) function Publish(DataPaths,scriptPath, figure, options)
%%Publish(DataPaths,scriptPath, ID, figure, options) saves plot, data and measuring script % Publish(DataPaths,scriptPath, ID, figure, options) saves plot, data and measuring script
% %
% DataPaths contains the path(s) to the research data, for multiple files % DataPaths contains the path(s) to the research data, for multiple files
% use a cell array % use a cell array or ONE struct of variables (only the first struct will
% be exported)
% scriptPath contains the path to the script, this can be provided with % scriptPath contains the path to the script, this can be provided with
% the simple call of scriptPath = [mfilename('fullpath'),'.m'] % the simple call of scriptPath = [mfilename('fullpath'),'.m']
% %
% Options: % Options:
% Location sets the storage location. 'local' sets the storage location % Location sets the storage location. 'local' sets the storage location
% to the current folder (an export folder will be created), 'manual' opens % to the current folder (an export folder will be created), 'manual' opens
% a explorer window, where you can choose the folder. If you define a export % an explorer window, where you can choose the folder. If you define a export
% path in the config file, this will used per defaul (exportPath). % path in the config file, this will used per default (exportPath).
% remote path, that is defined in the config file. % remote path, that is defined in the config file.
% Two Methods are implemented 'individual' stores the data for % Two Methods are implemented 'individual' stores the data for
% each plot while 'centralized' uses a data folder and uses reference links % each plot while 'centralized' uses a data folder and uses reference links
% to the original data (hdf5 only). % to the original data (hdf5 only).
% 'ParentFolder' is the folder Name where the exported data is stored if an % 'ParentFolder' is the folder name where the exported data is stored if an
% path is used, PlotId will use this path as storagePath % path is used, PlotId will use this path as storagePath
% 'ConfigFileName' is needed for handling multiple config files (see example) % 'ConfigFileName' is needed for handling multiple config files (see example)
% 'CSV' turns a summary table of all exports on or off % 'CSV' turns a summary table of all exports on or off
...@@ -26,7 +27,7 @@ function Publish(DataPaths,scriptPath, figure, options) ...@@ -26,7 +27,7 @@ function Publish(DataPaths,scriptPath, figure, options)
% 'ForcePublish' will publish even if one step was not successful (not recommended) % 'ForcePublish' will publish even if one step was not successful (not recommended)
arguments arguments
DataPaths {mustBeDataPath} % location of the data-file(s) DataPaths % location of the data-file(s) and/or ONE struct of variables
scriptPath (1,:) {mustBeText} % location of the matlab script scriptPath (1,:) {mustBeText} % location of the matlab script
figure (1,:) {mustBeFigure} % Checks if figure is a figure object figure (1,:) {mustBeFigure} % Checks if figure is a figure object
options.Location {mustBeMember(options.Location ,{'local','exportPath','manual','CI-Test'})} = 'local' % storage path options.Location {mustBeMember(options.Location ,{'local','exportPath','manual','CI-Test'})} = 'local' % storage path
...@@ -37,22 +38,10 @@ arguments ...@@ -37,22 +38,10 @@ arguments
options.CSV (1,1) {mustBeNumericOrLogical} = true options.CSV (1,1) {mustBeNumericOrLogical} = true
options.ShowMessages(1,1) {mustBeNumericOrLogical} = false options.ShowMessages(1,1) {mustBeNumericOrLogical} = false
options.ForcePublish (1,1) {mustBeNumericOrLogical} = false %publish anyway options.ForcePublish (1,1) {mustBeNumericOrLogical} = false %publish anyway
end end
%% argument validation %% argument validation
%catch string and non cell inputs in DataPaths
if ~iscell(DataPaths)
DataPaths = {DataPaths}; %Cell array
end
% strings will cause problems, therefore chars are used % strings will cause problems, therefore chars are used
for i=1:numel(DataPaths)
if isstring(DataPaths{i})
DataPaths{i} = char(DataPaths{i});
end
end
if isstring(scriptPath) if isstring(scriptPath)
scriptPath = char(scriptPath); scriptPath = char(scriptPath);
end end
...@@ -95,6 +84,9 @@ if isempty(ID) ...@@ -95,6 +84,9 @@ if isempty(ID)
warning(msg); warning(msg);
end end
%% Create a Datapath object from Input
dataObj = PlotID.dataPath(DataPaths,ID);
%% read config file %% read config file
% there is only one config Object (handleClass) % there is only one config Object (handleClass)
configObj = PlotID.config(options.ConfigFileName); configObj = PlotID.config(options.ConfigFileName);
...@@ -124,7 +116,7 @@ switch options.Location ...@@ -124,7 +116,7 @@ switch options.Location
if isfolder(configObj.exportPath) if isfolder(configObj.exportPath)
storPath = configObj.exportPath; storPath = configObj.exportPath;
else else
msg = ['Your Export folder ', storPath, newline,... msg = ['Your Export folder ', configObj.exportPath, newline,...
'does not exist, check the config file - publishing not possible!']; 'does not exist, check the config file - publishing not possible!'];
dlgObj.error(msg); dlgObj.error(msg);
end end
...@@ -169,66 +161,17 @@ dlgObj.userMSG(msg); ...@@ -169,66 +161,17 @@ dlgObj.userMSG(msg);
% user functions % user functions
if options.CopyUserFCN if options.CopyUserFCN
[fList,pList] = matlab.codetools.requiredFilesAndProducts(scriptPath); toolboxList = PlotID.copyUserFCN(scriptPath, folderName, storPath, ID);
fList = fList(~ismember(fList,scriptPath)); % rmv script from list
fList = fList(~contains(fList,'config.json')); % rmv config.json from list
fList = PlotID.removePltIdFiles(fList); % Do not copy files that are part of PlotID
if ~isempty(fList)
PlotID.createFileCopy(fList,folderName,storPath,ID,'userFcn');
end
end end
%% Research data handling %% Research data handling
switch options.Method switch options.Method
case 'centralized' case 'centralized'
DataFolderName = 'data'; [status, msg] = PlotID.centralized(storPath, dataObj, folderName);
% check if data folder exists
if ~isfolder(fullfile(storPath,DataFolderName))
mkdir(fullfile(storPath,DataFolderName));
end
% to get relative Paths
currentPath = fullfile(storPath);
%list all files
fList = dir(fullfile(storPath,DataFolderName, ['**',filesep,'*.*']));
%get list of files and folders in any subfolder
fList = fList(~[fList.isdir]); %remove folders from list
fList = struct2table(fList);
% Check if the new plot is based on the original data-set
% copy the data(once)
for i=1:numel(DataPaths)
% check if identical file exists (status = 1)
[~, idx] = PlotID.fileCompare(DataPaths{i},fList);
% create Linked HDF5 files for identical files
if any(idx)
fList.path = fullfile(fList.folder,fList.name);
sourcePath = fList{idx,'path'};
if ~iscell(sourcePath)
sourcePath = {sourcePath};
end
relativeSourcePath = strrep(sourcePath,currentPath,'');
if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5
linkedHDFPath = fullfile(storPath,folderName);
PlotID.createLinkedHDF5(relativeSourcePath{1,1},linkedHDFPath);
end
else % no identical file exists
%Copy the file in data and create the links (if hdf5)
[dataPath, status, msg] = PlotID.createFileCopy(DataPaths{i},'data',storPath,ID,'dataCentral');
pathToData = strrep(dataPath,currentPath,'');
%WIP
if contains(DataPaths{i},{'.h5','.hdf5'}) % Linking only for HDF5
% and create also linked files in the plot folder
linkedHDFPath = fullfile(storPath,folderName);
[status] = PlotID.createLinkedHDF5(pathToData,linkedHDFPath);
end %if
end %if
end %for
clear DataFolderName
case 'individual' case 'individual'
% Create a copy of the research data % Create a copy of the research data
[~, status, msg] = PlotID.createFileCopy(DataPaths,folderName,storPath,ID, 'data'); [~, status, msg] = PlotID.createFileCopy(dataObj.DataPaths,folderName,storPath,ID, 'data');
end end
%temporary: %temporary:
dlgObj.rdFilesPublished = status; dlgObj.rdFilesPublished = status;
...@@ -247,7 +190,7 @@ meta.ProjectID = ID; ...@@ -247,7 +190,7 @@ meta.ProjectID = ID;
meta.CreationDate = datestr(now); meta.CreationDate = datestr(now);
meta.MatlabVersion = version; meta.MatlabVersion = version;
if options.CopyUserFCN if options.CopyUserFCN
meta.ToolboxVersions = pList; meta.ToolboxVersions = toolboxList;
end end
% write meta % write meta
metaPath = fullfile(storPath,folderName,'plotID_data.json'); metaPath = fullfile(storPath,folderName,'plotID_data.json');
...@@ -282,11 +225,13 @@ if dlgObj.success || options.ForcePublish ...@@ -282,11 +225,13 @@ if dlgObj.success || options.ForcePublish
end end
status = movefile(oldPath,newPath); %rename directory status = movefile(oldPath,newPath); %rename directory
end end
% delete tmp data
dataObj.cleanTmpFile();
%% CSV export %% CSV export
if options.CSV if options.CSV
T = table(); T = table();
T.research_Data = DataPaths'; T.PlotID(:) = {ID}; T.research_Data = dataObj.DataPaths'; T.PlotID(:) = {ID};
T.Author(:) = {configObj.configData.Author}; T.Author(:) = {configObj.configData.Author};
T.Script_Name(:) = {scriptPath}; T.Script_Name(:) = {scriptPath};
T.Storage_Location(:) = {newPath}; T.Storage_Location(:) = {newPath};
...@@ -310,21 +255,5 @@ function tf = mustBeFigure(h) ...@@ -310,21 +255,5 @@ function tf = mustBeFigure(h)
tf = strcmp(get(h, 'type'), 'figure') & isa(h, 'matlab.ui.Figure'); tf = strcmp(get(h, 'type'), 'figure') & isa(h, 'matlab.ui.Figure');
end end
function mustBeDataPath(DataPaths)
%checks if input is a valid DataPath object
if ~iscell(DataPaths)
DataPaths = {DataPaths};
end
tf = zeros(1,numel(DataPaths));
for i=1:numel(DataPaths)
tf(i) = ~isfile(DataPaths{i});
end
if any(tf)
eidType = 'mustBeDataPath:notaValidFilePath';
msgType = 'DataPaths must contain file-path(s)';
throwAsCaller(MException(eidType,msgType))
end
end
...@@ -24,6 +24,9 @@ arguments ...@@ -24,6 +24,9 @@ arguments
options.Position (1,2) {mustBeVector} = [1,0.4] % default for east options.Position (1,2) {mustBeVector} = [1,0.4] % default for east
options.Rotation (1,1) {mustBeReal} = NaN options.Rotation (1,1) {mustBeReal} = NaN
options.ConfigFileName (1,:) {mustBeText} = 'config.json' options.ConfigFileName (1,:) {mustBeText} = 'config.json'
options.PinToLegend (1,1) {mustBeNumericOrLogical} = false % Pins ID on Legend
options.QRcode (1,1) {mustBeNumericOrLogical} = false %experimental
options.QRsize (1,1) {mustBeNonnegative} = 0.15 % size of the QRCode
end end
if isempty(options.ProjectID) if isempty(options.ProjectID)
...@@ -34,7 +37,7 @@ end ...@@ -34,7 +37,7 @@ end
switch options.Location switch options.Location
case 'north' case 'north'
y = 1 - options.DistanceToAxis y = 1 - options.DistanceToAxis;
options.Position = [0.4,y]; options.Position = [0.4,y];
Rotation = 0; Rotation = 0;
case 'east' case 'east'
...@@ -73,16 +76,46 @@ IDs = cell(numel(figs),1); ...@@ -73,16 +76,46 @@ IDs = cell(numel(figs),1);
for n = 1:numel(figs) for n = 1:numel(figs)
IDs{n} = PlotID.CreateID; % Create ID IDs{n} = PlotID.CreateID; % Create ID
IDs{n} = [options.ProjectID,'-',IDs{n}]; % add options.ProjectID IDs{n} = [options.ProjectID,'-',IDs{n}]; % add options.ProjectID
axes = get(figs(n),'CurrentAxes'); % Axes object for text annotation pltAxes = get(figs(n),'CurrentAxes'); % Axes object for text annotation
% Limits for relative Positioning % Limits for relative positioning
ylim =get(axes,'YLim'); ylim =get(pltAxes,'YLim');
xlim =get(axes,'XLim'); xlim =get(pltAxes,'XLim');
%ID
if options.PinToLegend
if options.QRcode
warning(['PinToLegend and QRCode can not be used at the same time',...
newline, 'QRcode is deactivated.']);
options.QRcode = false;
end
lobj = findobj(figs(n), 'Type', 'Legend');
if isempty(lobj)
set(0, 'CurrentFigure', figs(n))
lobj = legend();
end
% new position based on legend
posVec = get(lobj,'Position');
options.Position(1) = posVec(1)+.04;
options.Position(2) = posVec(2);
end
% add text label
position = [options.Position(1), options.Position(2)]; position = [options.Position(1), options.Position(2)];
text(axes,position(1),position(2), IDs{n},'Fontsize',options.Fontsize,... t=text(pltAxes,position(1),position(2), IDs{n},'Fontsize',options.Fontsize,...
'Rotation',Rotation, 'VerticalAlignment','bottom','Color',... 'Rotation',Rotation, 'VerticalAlignment','bottom','Color',...
options.Color,'BackgroundColor','w', 'Units', 'normalized'); options.Color,'BackgroundColor','w', 'Units', 'normalized');
set(figs(n),'Tag', IDs{n}); set(figs(n),'Tag', IDs{n});
if options.QRcode
% this should be seen and use as a proof of concept
qrCode = PlotID.plotQR(IDs{n});
size = options.QRsize;
axes('Position',[position(1)-.05 position(2)+0.1 size size]);
imshow(qrCode);
t.Visible = 'off';
end
end end
if numel(figs) == 1 if numel(figs) == 1
......
function [status, msg] = centralized(storPath, dataObj, folderName)
% CENTRALIZED stores the research files in a centrelized folder.
% Linked files are created for subsequent folders (HDF5 only).
%
% storPath for the Data
% dataObj contains tha data related information
% folderName is the Name of the storage Folder
msg = '';
warning(['Linked HDF5 can only be moved with their ',...
'respective master files in the ', dataObj.dataFolderName, ' folder.']);
% check if data folder exists
if ~isfolder(fullfile(storPath,dataObj.dataFolderName))
mkdir(fullfile(storPath,dataObj.dataFolderName));
end
% to get relative Paths
currentPath = fullfile(storPath);
%list all files
fList = dir(fullfile(storPath,dataObj.dataFolderName, ['**',filesep,'*.*']));
%get list of files and folders in any subfolder
fList = fList(~[fList.isdir]); %remove folders from list
fList = struct2table(fList);
% Check if the new plot is based on the original data-set
% copy the data(once)
for i=1:numel(dataObj.DataPaths)
% check if identical file exists (status = 1)
[~, idx] = PlotID.fileCompare(dataObj.DataPaths{i},fList);
% create l inked HDF5 files for identical files
if any(idx)
fList.path = fullfile(fList.folder,fList.name);
sourcePath = fList{idx,'path'};
if ~iscell(sourcePath)
sourcePath = {sourcePath};
end
relativeSourcePath = strrep(sourcePath,currentPath,'');
if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5
linkedHDFPath = fullfile(storPath,folderName);
[status] = PlotID.createLinkedHDF5(relativeSourcePath{1,1},linkedHDFPath);
end
else % no identical file exists
%Copy the file in data and create the links (if hdf5)
[dataPath, status, msg] = PlotID.createFileCopy(dataObj.DataPaths{i},...
'data',storPath,dataObj.ID,'dataCentral');
pathToData = strrep(dataPath,currentPath,'');
if ~status
return; % an error orccured
end
%WIP
if contains(dataObj.DataPaths{i},{'.h5','.hdf5'}) % Linking only for HDF5
% and create also linked files in the plot folder
linkedHDFPath = fullfile(storPath,folderName);
[status] = PlotID.createLinkedHDF5(pathToData,linkedHDFPath);
else
warning(['You use the centralized method for non hdf files,',...
newline, 'Your research files are located in the ',...
DataFolederName , 'folder.']);
status = true;
end %if
end %if
% add do not move message
doNotMove = ['do not move this folder without the ',...
dataObj.dataFolderName, ' folder'];
fid = fopen(fullfile(storPath,folderName,[doNotMove,'.txt']),'w');
fprintf(fid,doNotMove); fclose(fid);
end %for
end
\ No newline at end of file
function pList = copyUserFCN(scriptPath, folderName, storPath, ID)
% COPYUSERFCN copies all user functions, classes and toolboxes that are used
% by a script (scriptpath).
%
% All toolboxes and classes are copied as a whole.
% folderName, storPath and ID are required for createfilecopy
% see also createFileCopy
[fList,pList] = matlab.codetools.requiredFilesAndProducts(scriptPath);
fList = fList(~ismember(fList,scriptPath)); % rmv plot script itself from list
fList = fList(~contains(fList,'config.json')); % rmv config.json from list
fList = removePltIdFiles(fList); % Do not copy files that are part of PlotID
% copy Classes and Toolboxes as a whole
copyTBorClass(fList,'+', folderName, storPath, ID); % Toolboxes
copyTBorClass(fList,'@', folderName, storPath, ID); % Classes
%remove class and toolbox files from flist
fList = fList(~contains(fList,{'@','+'}));
% copy User FCN
if ~isempty(fList)
PlotID.createFileCopy(fList,folderName,storPath,ID,'userFcn');
end
end
function [fListClean] = removePltIdFiles(fList)
%removePltIdFiles removes functions that are part of PlotID out of flist
% Detailed explanation goes here
[~,names,ext] = fileparts(fList);
names = strcat(names, ext); % add ext for comparison
% Get a list of all .m files that are part of Plot id
packageContent = what('PlotID');
% packageContent.classes has no extensions
PltID_classlist = packageContent.classes;
% Class Methods need to be listed in an additional function
Class_flist = cell(1,numel(packageContent.classes)); %preallocate
for i=1:numel(packageContent.classes)
temp = what(['PlotID',filesep,'@',PltID_classlist{i}]);
Class_flist{i} = temp.m;
end
Class_flist = vertcat(Class_flist{:});
% all plotID .m files:
PltID_flist = [packageContent.m; Class_flist];
% Comparison and filter
fListClean = fList(~ismember(names,PltID_flist));
end
function [status, msg] = copyTBorClass(fList,leadChar, folderName, storPath, ID)
%copyTBorClass copies the Toolboxes or Classes that are part of flist
% lead char must be either '@' for Classes or '+' for Toolboxes
if any(contains(fList,leadChar))
list = fList(contains(fList, leadChar));
names = extractBetween(list,leadChar,filesep);
paths = extractBefore(list,strcat(leadChar,names));
fullPaths = strcat(paths,strcat(leadChar,names));
fullPaths = unique(fullPaths);
[~, status, msg] =PlotID.createFileCopy(fullPaths,...
folderName,storPath,ID,'class');
end %if
end
\ No newline at end of file
function [storagePaths, status, msg] = createFileCopy(filePaths,folderName,storPath,ID,type) function [storagePaths, status, msg] = createFileCopy(filePaths,folderName,storPath,ID,type)
% Creates a copy of the files (can be used for multiple paths in a cell array) % createFileCopy Creates a copy of the files (can be used for multiple
% paths in a cell array)
%
% folderName is the name of the exporting folder % folderName is the name of the exporting folder
% returns the storage paths were files were stored % returns the storage paths were files were stored
% type switches the mode depending on the data type
if ~iscell(filePaths) if ~iscell(filePaths)
%fixes Issue if filepath is a char and not a cell array %fixes Issue if filepath is a char and not a cell array
filePaths = {filePaths}; filePaths = {filePaths};
end end
try %try
storagePaths = cell(numel(filePaths,1)); storagePaths = cell(numel(filePaths,1));
for i = 1:numel(filePaths) for i = 1:numel(filePaths)
FileNameAndLocation = filePaths{i}; FileNameAndLocation = filePaths{i};
...@@ -29,6 +32,8 @@ try ...@@ -29,6 +32,8 @@ try
case 'userFcn' case 'userFcn'
%keep original name %keep original name
newfile = sprintf([name,ext]); newfile = sprintf([name,ext]);
case {'class','toolbox'}
newfile = name; % copy whole folder
otherwise otherwise
error([type,' is not a valid type for createFileCopy']) error([type,' is not a valid type for createFileCopy'])
end %switch end %switch
...@@ -36,24 +41,13 @@ try ...@@ -36,24 +41,13 @@ try
RemotePath = fullfile(storPath,folderName, newfile); RemotePath = fullfile(storPath,folderName, newfile);
% Check if remote file already exists % Check if remote file already exists
count = 0;
while isfile(RemotePath) && ismember(type,{'data','dataCentral'}) if isfile(RemotePath) && ismember(type,{'data','dataCentral'})
% Add a Sufix number to new file name % Add a Sufix number to new file name
% TODO add more inteligent way then a simple sufix
count = count + 1;
[~,name,ext] = fileparts(RemotePath); [~,name,ext] = fileparts(RemotePath);
if count < 2
RemotePath = fullfile(storPath,folderName,...
[name,'_',num2str(count),ext]);
else
RemotePath = fullfile(storPath,folderName,...
[name(1:end-length(num2str(count))),num2str(count),ext]);
end
[~, name, ~] = fileparts(RemotePath);
% User Dialog
msg = ['Filename ',name,... msg = ['Filename ',name, ' already exists in the data folder' newline,...
' already exists in the data folder' newline,...
' PlotID will add an suffix if you continue.' newline,... ' PlotID will add an suffix if you continue.' newline,...
' This can cause serious confusions.']; ' This can cause serious confusions.'];
warning(msg); warning(msg);
...@@ -62,20 +56,33 @@ try ...@@ -62,20 +56,33 @@ try
if ismember(m,{'N','n'}) if ismember(m,{'N','n'})
errorMSG = ['Filename already exists in data folder.' newline,... errorMSG = ['Filename already exists in data folder.' newline,...
' Rename the File and restart PlotID.']; ' Rename the File and restart PlotID.'];
error(); error(errorMSG);
end end
% add sufix
RemotePath = fullfile(storPath,folderName,...
[name,'_1',ext]);
% auto count until a sufix is reached that did not
% exist. (User is only asked once)
count = 0;
while isfile(RemotePath)
count = count + 1;
[~,name,~] = fileparts(RemotePath);
RemotePath = fullfile(storPath,folderName,...
[name(1:end-length(num2str(count-1))),num2str(count),ext]);
end end
end%if
copyfile(FileNameAndLocation,RemotePath); copyfile(FileNameAndLocation,RemotePath);
storagePaths{i} = RemotePath; storagePaths{i} = RemotePath;
end end %for
status = true; status = true;
msg =([type, ' successfully published']); msg =([type, ' successfully published']);
catch % catch
status = false; % status = false;
warning([type,' export was not successful']) % warning([type,' export was not successful'])
if exist('errorMSG') % if exist('errorMSG')
error(errorMSG); % error(errorMSG);
end % end
end %try % end %try
end %function end %function
function [status] = createLinkedHDF5(SourceFile,TargetPath) function [status] = createLinkedHDF5(SourceFile,TargetPath)
% createLinkedHDF5 creates a HDF file that references the Sourcefile % createLinkedHDF5 creates a HDF file that references the Sourcefile
% TargetPath is the storage location, ID the foldername % TargetPath is the storage location
% Status returns true if the function was successfull % Status returns true if the function was successfull
plist_id = 'H5P_DEFAULT'; plist_id = 'H5P_DEFAULT';
......
function [status, id] = fileCompare(filename,fileList) function [status, id] = fileCompare(filename,fileList)
%% fileCompare checks if file1 is (binary) identical to a file in filelist % fileCompare checks if file1 is (binary) identical to a file in filelist
% it returns a status and the id of the identical file % it returns a status and the id of the identical file
%
% the functions uses the java libraries from matlab for windows systems % the functions uses the java libraries from matlab for windows systems
% or the unix function diff % or the unix function diff because of performance issues with windows
% because of performance issues with windows system calls in matlab % system calls in matlab
if isempty(fileList) if isempty(fileList)
% no comparison necessary % no comparison necessary
......
function [IDf,PrjID, Str] = friendlyID(ID) function [IDf,PrjID, Str] = friendlyID(ID)
% FriendlyID Changes the Hex Number to a human friendly datetime and dateStr % FriendlyID Changes the Hex Number to a human friendly datetime and dateStr
%
% IDf ID as DateTime Object, PrjID returns the ProjectID, Str returns the % IDf ID as DateTime Object, PrjID returns the ProjectID, Str returns the
% timestamp as String % timestamp as String
......
function img = plotQR(qrTxt, size)
% plotQR creates a QR code based on qrTxt by calling a qrserver (depends on
% API)
% size specifies the absolut size of the qr code (pixels)
% special thanks to J.Stifter for this suggestion
arguments
qrTxt {mustBeTextScalar} = 'example';
size (1,2) {mustBeInteger} = [150, 150];
end
m = size(1);
n = size(2);
base_api = 'https://api.qrserver.com/v1/create-qr-code/?size=%dx%d&data=%s';
request = sprintf(base_api, m, n, qrTxt);
options = weboptions;
options.Timeout = 5;
img = webread(request, options);
img =logical(img);
end
function [fListClean] = removePltIdFiles(fList)
%removePltIdFiles removes functions that are part of PlotID out of flist
% Detailed explanation goes here
[~,names,ext] = fileparts(fList);
names = strcat(names, ext); % add ext for comparison
% Get a list of all .m files that are part of Plot id
packageContent = what('PlotID');
% packageContent.classes has no extensions
PltID_classlist = packageContent.classes;
% Class Methods need to be listed in an additional function
Class_flist = cell(1,numel(packageContent.classes)); %preallocate
for i=1:numel(packageContent.classes)
temp = what(['PlotID',filesep,'@',PltID_classlist{i}]);
Class_flist{i} = temp.m;
end
Class_flist = vertcat(Class_flist{:});
% all plotID .m files:
PltID_flist = [packageContent.m; Class_flist];
% Comparison and filter
fListClean = fList(~ismember(names,PltID_flist));
end
...@@ -6,8 +6,6 @@ function replaceLinkedHDF5(linkedFilepath) ...@@ -6,8 +6,6 @@ function replaceLinkedHDF5(linkedFilepath)
% Filepath is the location of the File that contains the link. The % Filepath is the location of the File that contains the link. The
% filepath to the linked data has to be present in the file itself. % filepath to the linked data has to be present in the file itself.
%% Check whether the only Objects present are links %% Check whether the only Objects present are links
h5inf = h5info(linkedFilepath); h5inf = h5info(linkedFilepath);
......
# V0.3 # V1.0 RC1
- Add changelog - Add changelog
- Add support for file or function name as scriptPath - Add support for file or function name as scriptPath
- Fix a Bug in HDF linking - Add support for passing Variables in publish
- Move centralized method in fuction
- Improve usability
- Improve documentation
clear; close all; clc;
%% Tag the plot with a QR code (experimental)
% here the work flow for tagging the plot with a QR code is shown
% the content of the qr code is the ID
% plots and data
fig(1) = figure;
[x1, y1, datapath1] = createExampleData('matlab');
plot(x1,y1,'-b'); box off; hold on; set(gca, 'TickDir', 'out', 'YLim', [0,4]);
%% 1. Tag plot with QRcode
% QR size is the relative size of the QR code (0.15 default)
[fig, IDs] = PlotID.TagPlot(fig,'Location','southeast','QRcode',true, 'QRsize', 0.18);
File moved
...@@ -23,3 +23,11 @@ plot(x.^2,y,'-r'); ...@@ -23,3 +23,11 @@ plot(x.^2,y,'-r');
[fig2, ID] = PlotID.TagPlot(fig2); [fig2, ID] = PlotID.TagPlot(fig2);
PlotID.Publish(datapath,scriptPath, fig2, 'Method','centralized') PlotID.Publish(datapath,scriptPath, fig2, 'Method','centralized')
%% Note:
% If you rerun this script PlotId will tell you that a identical named (but
% not binary idetical) file exists in the data folder. This is intended,
% due protect the user from overwritting non (binary) identical files. The
% reason for this is that two hdf files with the same data are not idetical
% when recreated (see line 11). Usually you would use an existing file
% without changing it.
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment