From 1f69d192f3257d01614844bfbcbe385d1e60dc5c Mon Sep 17 00:00:00 2001 From: Jan Lemmer <jan.lemmer@fst.tu-darmstadt.de> Date: Tue, 12 Oct 2021 14:56:49 +0200 Subject: [PATCH] clean commit --- {fcn_core => +PlotID}/CreateID.m | 7 +- +PlotID/Publish.m | 190 +++++++++ {fcn_core => +PlotID}/TagPlot.m | 51 ++- +PlotID/createLinkedHDF5.m | 32 ++ +PlotID/fileCompare.m | 56 +++ fcn_help/FriendlyID.m => +PlotID/friendlyID.m | 2 +- {fcn_help => +PlotID}/removePltIdFiles.m | 2 +- {fcn_help => +PlotID}/replaceLinkedHDF5.m | 0 .gitignore | 8 + .gitlab-ci.yml | 10 + CI_files/default_test.m | 17 +- CI_files/runner_test.m | 7 + LICENSE | 373 ------------------ PlotID_Demo.m | 74 ++++ README.md | 112 +++++- example-config.json | 5 + example.m | 110 +++--- fcn_core/Publish.m | 104 ----- fcn_help/createFileCopy.m | 52 --- fcn_help/createLinkedHDF5.m | 20 - fcn_help/fileCompare.m | 49 --- 21 files changed, 613 insertions(+), 668 deletions(-) rename {fcn_core => +PlotID}/CreateID.m (85%) create mode 100644 +PlotID/Publish.m rename {fcn_core => +PlotID}/TagPlot.m (59%) create mode 100644 +PlotID/createLinkedHDF5.m create mode 100644 +PlotID/fileCompare.m rename fcn_help/FriendlyID.m => +PlotID/friendlyID.m (91%) rename {fcn_help => +PlotID}/removePltIdFiles.m (86%) rename {fcn_help => +PlotID}/replaceLinkedHDF5.m (100%) create mode 100644 .gitlab-ci.yml create mode 100644 CI_files/runner_test.m delete mode 100644 LICENSE create mode 100644 PlotID_Demo.m create mode 100644 example-config.json delete mode 100644 fcn_core/Publish.m delete mode 100644 fcn_help/createFileCopy.m delete mode 100644 fcn_help/createLinkedHDF5.m delete mode 100644 fcn_help/fileCompare.m diff --git a/fcn_core/CreateID.m b/+PlotID/CreateID.m similarity index 85% rename from fcn_core/CreateID.m rename to +PlotID/CreateID.m index 42ec2b2..2579717 100644 --- a/fcn_core/CreateID.m +++ b/+PlotID/CreateID.m @@ -1,5 +1,5 @@ function [ID] = CreateID(method) -%CreateID Creates an Identifier (char) +%CreateID Creates an identifier (char) % Creates an (sometimes unique) identifier based on the selected method % if no method is selected method 1 will be the default method arguments @@ -10,10 +10,11 @@ switch method case 1 % UNIX Time in seconds as HEX ID = posixtime(datetime('now')); %get current Unix time ID = dec2hex(int32(ID)); % get it as Hex - pause(0.5); %Pausing for unique IDs + pause(1); %Pausing for unique IDs case 2 % random UUID from Java 128 bit %Static factory to retrieve a type 4 (pseudo randomly generated) UUID. - % The UUID is generated using a cryptographically strong pseudo random number generator. + % The UUID is generated using a cryptographically strong pseudo + % random number generator. temp = java.util.UUID.randomUUID; ID = temp.toString; otherwise diff --git a/+PlotID/Publish.m b/+PlotID/Publish.m new file mode 100644 index 0000000..fcd7772 --- /dev/null +++ b/+PlotID/Publish.m @@ -0,0 +1,190 @@ +function Publish(DataPaths, ID, figure, options) +%Publishes saves plot, data and measuring script +% Location sets the storage location. 'local' sets the storage location +% to the current folder (an export folder will be created), 'server' is a +% remote path, that is defined in the config file. +% Two Methods are implemented 'individual' stores the data for +% each plot while 'centralized' uses a data folder and uses reference links +% to the original data (hdf5 only). +% ParentFolder is the folder Name where the exported data is stored if an +% path is used, PlotId will use this path a storagePath + +arguments + DataPaths + ID (1,:) {mustBeNonzeroLengthText} % ID must be provided + figure (1,:) {mustBeFigure} % Checks if figure is a figure object + options.Location {mustBeMember(options.Location ,{'local','server','manual','CI-Test'})} = 'local' % storage path + options.Method {mustBeMember(options.Method ,{'individual','centralized'})} = 'individual' + options.ParentFolder (1,:) {mustBeText} = 'export' + options.CopyUserFCN (1,1) {mustBeNumericOrLogical} = true + options.CSV (1,1) {mustBeNumericOrLogical} = false +end + +%catch multiple figures in fig +if numel(figure) > 1 + figure = figure(1); + msg = ['Publish is designed for handeling one figure at once' newline,... + '- publishes uses only the first figure.' newline , ... + 'Consider an external for loop for multi figure export as provided in example.m']; + warning(msg); +end + +%% read config file +try + txt = fileread('config.json'); + config = jsondecode(txt); + configError = false; +catch + msg = ['Error while reading the config file' newline,... + ' publishing on server not possible']; + warning(msg); + configError = true; +end + +%% storage location +switch options.Location + case 'local' + if contains(options.ParentFolder, {'/','\'}) + storPath = options.ParentFolder; + else + % use the script path as export path + scriptPath = fileparts(DataPaths.script); + storPath = fullfile(scriptPath,options.ParentFolder); + end + case 'server' %from config File + storPath = config.ServerPath; + case 'manual' %UI + storPath = uigetdir(); + case 'CI-Test' + storPath = fullfile(pwd,'CI_files',options.ParentFolder); +end +folderName = char(ID); + +%% Create Data-Directory +if isfolder(fullfile(storPath,folderName)) + error(['Folder ',folderName, ' exists - Plot was already published ']); +elseif mkdir(fullfile(storPath,folderName)) +else + error('Directory could not be created - check remote path and permissions'); +end +disp(['publishing of ', ID, ' started']); + +%% Create a Copy of the script and user functions(optional) +% script +PlotID.createFileCopy({[DataPaths.script,'.m']},folderName,storPath,ID, 'script'); + +% user functions +[fList,pList] = matlab.codetools.requiredFilesAndProducts(DataPaths.script); +if options.CopyUserFCN + fList = fList(~ismember(fList,[DataPaths.script,'.m'])); % 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 plot ID + if ~isempty(fList) + PlotID.createFileCopy(fList,folderName,storPath,ID,'userFcn'); + end +end + +%% Research data handeling +switch options.Method + case 'centralized' + DataFolderName = 'data'; + % 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, '**\*.*')); + %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.rdata) + % check if identical file exists (status = 1) + [~, idx] = PlotID.fileCompare(DataPaths.rdata{i},fList); + % create Linked HDF5 files for identical files + if any(idx) + fList.path = fullfile(fList.folder,fList.name); + sourcePath = fList{idx,'path'}; + relativeSourcePath = strrep(sourcePath,currentPath,''); + + if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5 + PlotID.createLinkedHDF5(relativeSourcePath{1,1},storPath,ID); + end + else % no identical file exists + %Copy the file in data and create the links (if hdf5) + [dataPath] = PlotID.createFileCopy(DataPaths.rdata{i},'data',storPath,ID,'dataCentral'); + relativeDataPath = strrep(dataPath,currentPath,''); + %WIP + if contains(DataPaths.rdata{i},{'.h5','.hdf5'}) % Linking only for HDF5 + % and create also linked files in the plot folder + PlotID.createLinkedHDF5(relativeDataPath,storPath,ID); + end %if + end %if + end %for + clear DataFolderName + case 'individual' + % Create a copy of the research data + PlotID.createFileCopy(DataPaths.rdata,folderName,storPath,ID, 'data'); +end +%% Write Config File + +if ~configError %config File must exist + % copy config file + configPath = PlotID.createFileCopy('config.json',folderName,... + storPath,ID, 'data'); +else + configPath = fullpath(storPath,folderName, 'config.json'); + config = struct(); + if ispc + config.author = getenv('USERNAME'); + end +end +% add further Metadata +config.ProjectID = ID; +config.CreationDate = datestr(now); +config.MatlabVersion = version; +config.ToolboxVersions = pList; + +%write config +fid = fopen(char(configPath),'w'); +txt = jsonencode(config,'PrettyPrint',true); +fprintf(fid,txt); +fclose(fid); + + +%% Export the Plot +try + PlotName = [ID,'_plot']; % plotname + RemotePath = fullfile(storPath ,folderName, PlotName); + % Matlab figure + savefig(figure,RemotePath); + % the png should only be a preview + exportgraphics(figure,[RemotePath,'.png'],'Resolution',300); +catch + warning('Plot export was not successful') +end + +disp(['publishing of ', ID , ' done']); + +% CSV EXport +if options.CSV + T = table(); + T.research_Data = DataPaths.rdata'; T.PlotID(:) = {ID}; + T.Script_Name(:) = {[DataPaths.script,'.m']}; + T.Storage_Location(:) = {storPath}; + T.Date(:) = {datestr(now)}; + T = movevars(T,'PlotID','before',1); + writetable(T, fullfile(storPath, 'overview_table.csv'),'WriteMode','append'); +end + +end %function + +function tf = mustBeFigure(h) +%checks if input is a figure object + tf = strcmp(get(h, 'type'), 'figure') & isa(h, 'matlab.ui.Figure'); +end diff --git a/fcn_core/TagPlot.m b/+PlotID/TagPlot.m similarity index 59% rename from fcn_core/TagPlot.m rename to +PlotID/TagPlot.m index 4fac128..4a59658 100644 --- a/fcn_core/TagPlot.m +++ b/+PlotID/TagPlot.m @@ -1,8 +1,11 @@ -function [figs, ID] = TagPlot(figs, prefix, options) +function [figs, IDs] = TagPlot(figs, options) %TagPlot adds IDs to figures -% The ID is placed visual on the figure window and as Tag (Property of figure) -% TagPlot can tag multiple figures at once -% prefix is the project number (string or char) +% The ID is placed visual on the figure window and as Tag (property of figure) +% TagPlot can tag multiple figures at once. +% If a single Plot is taged IDs is a char, otherwise it is a cell array of +% chars +% options.ProjectID is the project number (string or char), if empty the ID from the +% config file is used % % The ID is placed on the 'east' per default, if you want it somwhere % else, use the 'Location' option. 'north','east','south','west' are @@ -10,15 +13,29 @@ function [figs, ID] = TagPlot(figs, prefix, options) % 'Position' (relative to your x- and y-axis limits) arguments figs (1,:) {mustBeFigure} - prefix (1,:) {mustBeText}= '' + options.ProjectID (1,:) {mustBeText}= '' options.Fontsize (1,1) {mustBeInteger} = 8 options.Location (1,:) {mustBeText} = 'east' options.Position (1,2) {mustBeVector} = [1,0.4] % default for east options.Rotation (1,1) {mustBeInteger} = 0 end -if isempty(prefix) - warning('no project prefix defined') +if isempty(options.ProjectID) + try + txt = fileread('config.json'); + config = jsondecode(txt); + catch + config =struct; + config.ProjectID = ''; + warning("No ProjectID was definded and no config.json could be found"); + + end + + if ~isempty(config.ProjectID) + options.ProjectID = config.ProjectID; + else + warning('no project options.ProjectID defined') + end end switch options.Location @@ -38,27 +55,33 @@ switch options.Location % Check if Position is valid if ~all(0 <= options.Position & options.Position <= 1) options.Position = [1,0.4]; - warning('options.Position is not valid, TagPlot default values instead'); + warning('options.Position is not valid, TagPlot uses default values instead'); end otherwise % set default position warning([options.Location, ' is not a defined location, TagPlot uses location east instead']); options.Location = 'east'; options.Position = [1,0.4]; end - + +IDs = cell(numel(figs),1); + for n = 1:numel(figs) - ID = CreateID; % Create ID - ID = [prefix,'-',ID]; % add Prefix + IDs{n} = PlotID.CreateID; % Create ID + IDs{n} = [options.ProjectID,'-',IDs{n}]; % add options.ProjectID axes = get(figs(n),'CurrentAxes'); % Axes object for text annotation % Limits for relative Positioning ylim =get(axes,'YLim'); xlim =get(axes,'XLim'); %ID position = [options.Position(1)*xlim(2), options.Position(2)*ylim(2)]; - text(axes,position(1),position(2), ID,'Fontsize',options.Fontsize,... + text(axes,position(1),position(2), IDs{n},'Fontsize',options.Fontsize,... 'Rotation',options.Rotation, 'VerticalAlignment','bottom','Color',... 0.65*[1 1 1],'BackgroundColor','w'); - set(figs(n),'Tag', ID); - + set(figs(n),'Tag', IDs{n}); +end + +if numel(figs) == 1 + % use char instead of a cell arry for a single ID + IDs = IDs{1}; end end diff --git a/+PlotID/createLinkedHDF5.m b/+PlotID/createLinkedHDF5.m new file mode 100644 index 0000000..8fecfae --- /dev/null +++ b/+PlotID/createLinkedHDF5.m @@ -0,0 +1,32 @@ +function [status] = createLinkedHDF5(SourceFile,TargetPath,ID) +%createLinkedHDF5 creates a HDF file that references the Sourcefile +% TargetPath is the storage location, ID the foldername +% Status returns true if the function was sucessfull + +plist_id = 'H5P_DEFAULT'; + +%catches error of wrong file type +if iscell(SourceFile) + SourceFile = SourceFile{1}; +end + +[~,filename,ext] = fileparts(SourceFile); + +% try + %old + %fid = H5F.create(fullfile(TargetPath,ID,[ID,'_data.h5'])); + + fid = H5F.create(fullfile(TargetPath,ID,[filename,ext])); + %create External Link to Sourcefile in the Group linkToExternal + H5L.create_external(['..\',SourceFile],'/',fid, SourceFile ,plist_id,plist_id); + %H5L.create_external(['..\data\',SourceFile],'/',fid, SourceFile ,plist_id,plist_id); %original + H5F.close(fid); + disp([fullfile(TargetPath,ID,[filename,ext]),' created']); + status = 1; +% catch +% warning('No linked HDF file was created'); +% status = 0; +% end + +end + diff --git a/+PlotID/fileCompare.m b/+PlotID/fileCompare.m new file mode 100644 index 0000000..9d0f969 --- /dev/null +++ b/+PlotID/fileCompare.m @@ -0,0 +1,56 @@ +function [status, id] = fileCompare(filename,fileList) +%% fileCompare checks if file1 is (binary) identical to a file in filelist +% it returns a status and the id of the identical file +% the functions uses the java libraries from matlab for windows systems +% or the unix function diff +% because of performance issues with windows system calls in matlab + +if isempty(fileList) + % no comparison necessary + status =false; + id = 0; + return +end + +[~,~,ext1] = fileparts(filename); +id = zeros(height(fileList),1); + +for i=1:height(fileList) + [~,~,ext2] = fileparts(fileList{i,'name'}); + + if ~isequal(ext1,ext2) + %warning('File extension are not identical'); + status = false; + continue + end + + filepath = fullfile(fileList{i,'folder'},fileList{i,'name'}); + + %% comparison with java function + % TODO test paths with spaces + status = comparejava(filename, char(filepath)); + + if status == 1 + id(i) = 1; + id =logical(id); %bugfix + return; + else + % Status can also be any other number e.g. 2 + id(i) = 0; + end + + id =logical(id); %bugfix +end + +end + +function is_equal = comparejava(file1, file2) +%% Utilizing java functionalities for inter-os comparison of binary files +% file1 and file2 should be full filepaths + +file1 = javaObject('java.io.File',file1); +file2 = javaObject('java.io.File',file2); +is_equal = javaMethod('contentEquals','org.apache.commons.io.FileUtils',file1,file2); + +is_equal = double(is_equal); % Conversion for compatibility reasons +end diff --git a/fcn_help/FriendlyID.m b/+PlotID/friendlyID.m similarity index 91% rename from fcn_help/FriendlyID.m rename to +PlotID/friendlyID.m index e18834b..cdac106 100644 --- a/fcn_help/FriendlyID.m +++ b/+PlotID/friendlyID.m @@ -1,4 +1,4 @@ -function [IDf,PrjID, Str] = FriendlyID(ID) +function [IDf,PrjID, Str] = friendlyID(ID) %FriendlyID Changes the Hex Number to a human friendly datetime and dateStr % IDf ID as DateTime Object, PrjID returns the ProjectID, Str returns the % timestamp as String diff --git a/fcn_help/removePltIdFiles.m b/+PlotID/removePltIdFiles.m similarity index 86% rename from fcn_help/removePltIdFiles.m rename to +PlotID/removePltIdFiles.m index 3080c22..37ef182 100644 --- a/fcn_help/removePltIdFiles.m +++ b/+PlotID/removePltIdFiles.m @@ -7,7 +7,7 @@ function [fListClean] = removePltIdFiles(fList) names = strcat(names, ext); % add ext for comparison % Get a list of all .m files that are part of Plot id -PltID_flist = struct2table([dir('fcn_help'); dir('fcn_core')]); %get list of files +PltID_flist = struct2table(dir('+PlotID')); %get list of files [~,~,PltID_flist.ext(:)] = fileparts(PltID_flist.name(:)); % add ext column PltID_flist = PltID_flist(strcmp(PltID_flist.ext,'.m'),:); diff --git a/fcn_help/replaceLinkedHDF5.m b/+PlotID/replaceLinkedHDF5.m similarity index 100% rename from fcn_help/replaceLinkedHDF5.m rename to +PlotID/replaceLinkedHDF5.m diff --git a/.gitignore b/.gitignore index 3d5fc69..708bea6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# config file changes +config.json + # Windows default autosave extension *.asv @@ -28,11 +31,16 @@ codegen/ test*.m test123_data.h5 + # files that are created in example.m testdata_2.h5 +testdata2.h5 test_data.mat export/* # Octave session info octave-workspace test_data.mat + +#logs +log.txt diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..7901609 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,10 @@ +#Based on STFS Workshop +stages: + - Run +Test Code: + stage: Run + tags: + - matlab + script: + - ./CI_files/runtest.ps1 + - cat log2.txt diff --git a/CI_files/default_test.m b/CI_files/default_test.m index 515ad37..505c360 100644 --- a/CI_files/default_test.m +++ b/CI_files/default_test.m @@ -3,7 +3,12 @@ function [result] = default_test() % Detailed explanation goes here clear; clc; close all; -addpath('./fcn_core','./fcn_help'); + +% clean up, if previous run failed +try + delete CI_files/export/* CI_files/*.mat CI_files/*.h5 + rmdir('CI_files/export','s'); +end ProjectID = 'Test01'; %% Data @@ -35,7 +40,7 @@ plot(x1,y1,'-r'); %% Tag the plot try - [figs, ID] = TagPlot(fig, ProjectID); + [figs, ID] = PlotID.TagPlot(fig,'ProjectID', ProjectID); %% call a dummy function a=1; @@ -50,13 +55,15 @@ try % file name of the data path.rdata = {dataset1,dataset2} ; % don't forget the extension - Publish(path, ID, figs, 'Location', 'CI-Test') + PlotID.Publish(path, ID, figs, 'Location', 'CI-Test') + result = true; % clean up delete CI_files/export/* CI_files/*.mat CI_files/*.h5 rmdir('CI_files/export','s'); - result = true; - clc; + + clear; clc; + catch result = false; warning('simple_test failed'); diff --git a/CI_files/runner_test.m b/CI_files/runner_test.m new file mode 100644 index 0000000..496afd8 --- /dev/null +++ b/CI_files/runner_test.m @@ -0,0 +1,7 @@ +function [result] = runner_test() +%RUNNER_TEST testing function to test, if the runner is set up properly +result = true; + +exit(result); +end + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a612ad9..0000000 --- a/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/PlotID_Demo.m b/PlotID_Demo.m new file mode 100644 index 0000000..766ad17 --- /dev/null +++ b/PlotID_Demo.m @@ -0,0 +1,74 @@ +%% Example Script +% This Script is meant to demonstrate the capabilities of the PlotID tool. + +%% Clear Environment +clear; clc; close all; +addpath('CI_files'); % Test scripts +try + delete testdata2.h5; +end + +%% Set ProjectID +% ProjectID can also be set in the config file +% Leave empty for using the ID from the config file +ProjectID = 'FST01'; + +%% Data +% Creating Random Data to use as data-file +x = linspace(0,7); +y = rand(1,100)+2; +dataset1 = 'test_data.mat'; +% use absolute paths for good practise +dataset1 = fullfile(pwd, dataset1); +save(dataset1,'x','y'); + +% some data as .h5 +x1 = linspace(0,2*pi); +y1 = sin(x1)+.5*sin(2*x1)+2; + +% define file path & name + +fpath = fullfile(pwd,"./testdata2.h5"); +dataset2 = fullfile(pwd,'testdata2.h5'); + +% create hdf5 file and dataset > write data to hdf5 file / dataset +h5create(fpath, "/x1", size(x1), "Datatype", class(x1)) +h5create(fpath, "/y1", size(y1), "Datatype", class(y1)) +h5write(fpath, "/x1", x1) +h5write(fpath, "/y1", y1) + +%% Plotting +% This is still part of a normal script to produce plots. +% Make sure to save each figure in a variable to pass to PlotID-functions. +fig(1) = figure; +set(gcf,'Units','centimeters','PaperUnits','centimeters','PaperSize',[9 7],... +'Position',[5 5 9 7]); +plot(x,y,'Color',0.5*[1 1 1]); +box off; hold on; +plot(x1,y1,'-k'); +set(gca, 'TickDir', 'out', 'YLim', [0,4],'YTick',[0:1:4],'XLim',[0,6]); +%fstplt.setfiguresize('1/2ppt16:9'); +%fstplt.pimpplot; + +%% Example 1: single plot based on two data-sets + +%% Tag the plot +% PlotID Implementation starts here. +% TagPlot adds a visible ID to the figure(s) and to the figures property +% 'Tag' +[fig, ID] = PlotID.TagPlot(fig, 'ProjectID', ProjectID); + +%% Publishing +% Second part of plotID +% The functions needs the file location, the location of the data and the +% figure and can take several options. +path.script = mfilename('fullpath'); % filename of the m.script +% file names of the datasets +path.rdata = {dataset1,dataset2} ; % don't forget the extension + +PlotID.Publish(path, ID, fig(1), 'Location', 'local' ,'Method','individual') + + + +%% End + diff --git a/README.md b/README.md index 7ee43f2..a9e8270 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,111 @@ -# Plot_Identifier +**PlotID** + +`PlotID` is a toolkit that labels your plots and figures and copies all associated data (research data, plotting script, user-functions and a copy of the figure) to the desired location. + +This version of `PlotID` is build for `MATLAB`. + +`PlotID` provides two core functions **TagPlot** and **Publish** which are described in detail below. + +Feel free to give feedback and feature requests or to take part in the development process. + + [TOC] + +# Quick User Guide +`PlotID` works in two Steps: + +1. tagging the plot +`[figs, IDs] = plotId.TagPlot(figs, options)` + + +2. publishing the plot and the associated data +`plotID.Publish(DataPaths, ID, figure, options)` + +`DataPaths.script = mfilename('fullpath');` contains the filename of the m.script + +`DataPaths.rdata = {dataset1, dataset2};` file names of the datasets (they most be at the path) + +# PlotID.TagPlot() +`[figs, IDs] = TagPlot(figs, options)` +**TagPlot** adds IDs to figures +The ID is placed visual on the figure window and as Tag (property of the figure) +**TagPlot** can tag multiple figures at once. If a single Plot is tagged, IDs is a char, otherwise it is a cell array of chars . + +<details><summary>detailed description</summary> + +_options_ \ +you find the options for TagPlot below. The data type is in curled braces and the default value follows the equal sign. + +- ProjectID {mustBeText}= '' +- Fontsize {mustBeInteger} = 8 +- Location {mustBeText} = 'east' +- Position {mustBeVector} = [1,0.4] +- Rotation {mustBeInteger} = 0 + +`options.ProjectID` is the project number (string or char), if empty the ID from the config file is used +The ID is placed on the 'east' of the figure per default, if you want it somwhere else, use the `'Location'` option. 'north', 'east', 'south', 'west' are predefined, otherwise use the `'custom'` option and provide the desired 'Position' as a vector relative to your x- and y-axis limits `[relX, relY]` . +</details> + +## CreateID() +`function [ID] = CreateID(method)` \ +CreateID Creates an identifier (char). It creates an (sometimes unique) identifier based on the selected method, if no method is selected method 1 will be the default method. + +1. **UNIX Time in seconds as HEX** \ +This is used by default due to its simplicity and it is human readable. +2. **random UUID from Java 128 bit.**\ +Static factory to retrieve a type 4 (pseudo randomly generated) UUID. The UUID is generated using a cryptographically strong pseudo random number generator. + +## friendlyID() +`[IDf,PrjID, Str] = friendlyID(ID)` \ +FriendlyID Changes the Hex Number to a human friendly *datetime* and *dateStr*. `IDf` returns the ID as DateTime Object, `PrjID` returns the ProjectID, `Str` returns the timestamp as String. \ +**This only works with ID method 1.** + + +# PlotID.Publish() +`Publish(DataPaths, ID, figure, options)` \ +Publishes saves plot, data and measuring script +Location sets the storage location. 'local' sets the storage location to the current folder (an export folder will be created), 'server' is a remote path, that is defined in the config file. Two Methods are implemented 'individual' stores the data for each plot while 'centralized' uses a data folder and uses reference links to the original data (hdf5 only). ParentFolder is the folder Name where the exported data is stored if a path is used, PlotId will use this path a storagePath + +<details><summary>detailed description</summary> + +_options_ \ +you find the options for publish below. The data is in curled braces and the default value follows the equal sign. + +- Location {mustBeMember(options.Location ,{'local','server','manual','CI-Test'})} = 'local' \ +'local' creates the folder in your current working path, 'server' on a remote path that needs to be specified in the config file. 'manual' opens an UI Window where the path must be choosen, 'CI-Test' is for CI testing only. +- Method {mustBeMember(options.Method ,{'individual','centraliced'})} = 'individual'\ +'individual' each folder contains the assigned data files. (recommended for small file sizes and for sharing). +'centralized' one central data folder is used for saving the research data files, the subfolders contain linked hdf5-files (if hdf5 is used). This is recommended, if many plots are made from the same data set. Attention, the linked HDF5 will not work when a subfolder was moved or the data folder was deleted. +- ParentFolder {mustBeText} = 'export'\ +An individual folden name can be set with this option. +- CopyUserFCN {mustBeNumericOrLogical} = true \ +All user functions that are used by script that calls publish will be exported per default as well. Set this to false (not recommended) to prevent this. +- CSV {mustBeNumericOrLogical} = false \ +An overview of all published plots and the associated data will be stored in a csv file. +</details> + +## createFileCopy () +`[] = createFileCopy(filePaths,folderName,storPath,ID,type)`\ +Creates a copy of the files (can be used for multiple paths in a cell array). folderName is the name of the exporting folder +## createLinkedHDF () +`[status] = createLinkedHDF5(SourceFile,TargetPath,ID)` \ +createLinkedHDF5 creates a HDF file that references the Sourcefile. TargetPath is the storage location, ID the foldername, Status returns true if the function was sucessfull. +## fileCompare() +`[status, id] = fileCompare(filename,fileList)` \ +fileCompare checks if file1 is (binary) identical to a file in filelist, it returns a sttus and the id of the identical file. The function uses the windows system function fc or the unix function diff (not tested). +## removePltIdFiles() +`[fListClean] = removePltIdFiles(fList)` \ +removePltIdFiles removes functions that are part of PlotID out of flist. + +# How to use the .config file +The config file is a JSON-File. At the moment two options can be set in the config file, the project ID and the remote Path. + +``` +{ + "ProjectID": "your ProjectID", + "ServerPath": "\\\\Server\\Folder1\\Subfolder" +} +``` + +# Known Issues +# FAQs -Organisation und Beispiele aus den beiden Pilotprojekten zu Plotidentifiern diff --git a/example-config.json b/example-config.json new file mode 100644 index 0000000..9df3f40 --- /dev/null +++ b/example-config.json @@ -0,0 +1,5 @@ +{ + "Author": "Example Author" + "ProjectID": "AB01", + "ServerPath": "\\\\Server\\path\\folder" +} \ No newline at end of file diff --git a/example.m b/example.m index f208097..04aa8c1 100644 --- a/example.m +++ b/example.m @@ -3,40 +3,35 @@ %% Clear Environment clear; clc; close all; -addpath('fcn_core','fcn_help'); -addpath('CI_files'); % Test scripts try - delete testdata_2.h5; + delete testdata2.h5; end - %% Set ProjectID -% ProjectID - -% TODO: decide how projectID and optionally ORCID will be implemented -% ORCID placed on startup (alternative?) - projectID as persistent -% otherwise dialogue? -ProjectID = 'JL01'; - +% ProjectID can also be set in the config file +% Leave empty for using the ID from the config file +ProjectID = 'Example'; %% Data -% Creating Random Data to use as data-file +% only necessary for this example -x = linspace(0,7); -y = rand(1,100)+2; +% Creating Random Data to use as data-file +x = linspace(0,7); y = rand(1,100)+2; dataset1 = 'test_data.mat'; -save('test_data.mat','x','y'); +% Use absolute paths for good practise +dataset1 = fullfile(pwd,dataset1); +save(dataset1,'x','y'); -% some data as .h5 -x1 = linspace(0,2*pi); -y1 = sin(x1)+2; +% some data for the .h5 file +x1 = linspace(0,2*pi); y1 = sin(x1)+2; -% define file path & name -fpath = "./testdata_2.h5"; -dataset2 = 'testdata_2.h5'; +% define filepath & name +dataset2 = 'testdata2.h5'; +dataset2 = fullfile(pwd,dataset2); +fpath = dataset2; % create hdf5 file and dataset > write data to hdf5 file / dataset h5create(fpath, "/x1", size(x1), "Datatype", class(x1)) @@ -44,52 +39,79 @@ h5create(fpath, "/y1", size(y1), "Datatype", class(y1)) h5write(fpath, "/x1", x1) h5write(fpath, "/y1", y1) +%% function calls +% Place for post-processing of the data, or additional related code. +% example_fcn is a dummy function to show the functionality +a = 1; a = example_fcn(a); +p = betacdf(0.5,1,1); % to test toolboxes %% Plotting % This is still part of a normal script to produce plots. -% Make sure to save each figure in a variable to pass to PlotID-functions. +% Make sure to save each figure in a variable +% to pass it to PlotID-functions. fig(1) = figure; plot(x,y,'-k'); -box off -set(gca, 'TickDir', 'out', 'YLim', [0,4]); - -hold on -%fig(2) = figure; +box off; hold on; plot(x1,y1,'-r'); set(gca, 'TickDir', 'out', 'YLim', [0,4]); +%% Example 1: single plot based on two data-sets + %% Tag the plot % PlotID Implementation starts here. - -[figs, ID] = TagPlot(fig, ProjectID); - - - -%% call a dummy function -% Place for post-processing of the plot, or additional related code. -a=1; -a = example_fcn(a); +% TagPlot adds a visible ID to the figure(s) and to the figures property +% 'Tag' +[fig, ID] = PlotID.TagPlot(fig, 'ProjectID', ProjectID); %% Publishing % Second part of plotID -% The functions needs the file location, the location of the data and the -% figure and can take several options. -% TODO add explanations for Options +% The functions needs the file location of the script, the location of the +% data and the figure and can take several options (see readme). + path.script = mfilename('fullpath'); % filename of the m.script +% file names of the datasets -% file name of the dataset +%(defined above:) dataset1 = 'test_data.mat'; dataset2 = 'testdata2.h5' path.rdata = {dataset1,dataset2} ; % don't forget the extension -Publish(path, ID, figs, 'Location', 'local','Method','centraliced') +%call publishing +PlotID.Publish(path, ID, fig(1), 'Location', 'local' ,'Method','individual') + +%% Example 2: multiple plots plot, all based on dataset2 (hdf5) +% for individual data-sets, use an appropriate array + +fig(2) = figure; +plot(x,y,'-b'); +box off; hold on; +plot(x1,y1,'--k'); +set(gca, 'TickDir', 'out', 'YLim', [0,4]); + +% tag both plots +[fig, IDs] = PlotID.TagPlot(fig,'ProjectID', ProjectID); + +% data locations +path.script = mfilename('fullpath'); % filename of the m.script +% file names of the datasets +path.rdata = {dataset2} ; % don't forget the extension + +% publsihing via a for-loop +for i=1: numel(fig) + PlotID.Publish(path, IDs{i}, fig(i), 'Location', 'local',... + 'Method','individual'); +end %% Second Plot with identical data to test centralized method -% +% A central data folder is used for saving the research data files, the +% subfolders contain linked hdf5-files (if hdf5 is used). This is +% recommended, if many plots are made from the same data set. Attention, +% the linked HDF5 will not work when a subfolder was moved or the data +% folder was deleted fig2 =figure; plot(x,y,'-k'); hold on plot(x1,y1,'-r'); -[fig2, ID] = TagPlot(fig2, ProjectID); +[fig2, ID] = PlotID.TagPlot(fig2,'ProjectID', ProjectID); -Publish(path, ID, fig2, 'Location', 'local','Method','centraliced') \ No newline at end of file +PlotID.Publish(path, ID, fig2, 'Location', 'local','Method','centralized') diff --git a/fcn_core/Publish.m b/fcn_core/Publish.m deleted file mode 100644 index e6952d7..0000000 --- a/fcn_core/Publish.m +++ /dev/null @@ -1,104 +0,0 @@ -function Publish(DataPaths, ID, figures, options) -%Publishes Saves Plot, Data and Measuring script -% Detailed explanation goes here -% Location sets the storage location. local is in the current folder (an -% export folder will be created), server is a remote Path -% two Methods are implemented individual stores the data for each plot -% while centralized uses a data folder and uses reference links to the -% original data - -arguments - DataPaths - ID (1,:) {mustBeNonzeroLengthText} % ID must be provided - figures (1,:) {mustBeFigure} % Checks if Figures are figures - options.Location {mustBeMember(options.Location ,['local','server','CI-Test'])} = 'local' % storage path - options.Method {mustBeMember(options.Method ,['individual','centraliced'])} = 'individual' - options.CopyUserFCN (1,1) {mustBeNumericOrLogical} = true -end - -switch options.Location - case 'local' - storPath = fullfile(pwd,'export'); - case 'server' - storPath = '\\FST-220\Jans-50GB-SMB\Lemmer'; - case 'CI-Test' - storPath = fullfile(pwd,'CI_files','export'); -end -folderName = char(ID); - -%% Create Data-Directory -addpath(storPath); -if mkdir(fullfile(storPath,folderName)) -else - error('Directory could not be created - check remote path and permissions'); -end - -disp('Publishing started'); - -%% Create a Copy of the script and User functions(optional) -createFileCopy({[DataPaths.script,'.m']},folderName,storPath,ID, 'script'); - -if options.CopyUserFCN - [fList,pList] = matlab.codetools.requiredFilesAndProducts(DataPaths.script); - % plist contains the required MATLAB Toolboxes, maybe usefull in future - fList = fList(~ismember(fList,[DataPaths.script,'.m'])); % rmv script from list - fList = removePltIdFiles(fList); % Do not copy files that are part of plot ID - if ~isempty(fList) - createFileCopy(fList,folderName,storPath,ID,'userFcn'); - end -end - -%% Research data handeling -switch options.Method - case 'centraliced' % Work in progresss!!! - % check if data folder exists - if ~isfolder(fullfile(storPath,'data')) - mkdir(fullfile(storPath,'data')); - end - %list all files - fList = dir(fullfile(storPath,'data', '**\*.*')); %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.rdata) - % check if identical file exists (status = 1) - [~, idx] = fileCompare(DataPaths.rdata{i},fList); - % create Linked HDF5 files for identical files - if any(idx) - sourcePath = fList.name{idx}; % If there are multiple copies already, this only picks the last entry - if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5 - createLinkedHDF5(sourcePath,storPath,ID); - end - else % no identical file exists - createFileCopy(DataPaths.rdata{i},'data',storPath,ID,'dataCentral'); - end - end - case 'individual' - % Create a copy of the research data - createFileCopy(DataPaths.rdata,folderName,storPath,ID, 'data'); -end -%% Export the Plots -try - for i=1:numel(figures) - fig = figures(i); - PlotName = [ID,'_plot',num2str(i)]; % Der Plotnamen - RemotePath = fullfile(storPath ,folderName, PlotName); - % Matlab figure - savefig(fig,RemotePath); - exportgraphics(fig,[RemotePath,'.png'],'Resolution',300); - disp([num2str(i),' of ',num2str(numel(figures)),' figures exported']); - end -catch - warning('Plot export was not successful') -end - -disp(['publishing of ', ID , ' done']); - -end %function - -function tf = mustBeFigure(h) -%checks if input is a figure object - tf = strcmp(get(h, 'type'), 'figure') & isa(h, 'matlab.ui.Figure'); -end diff --git a/fcn_help/createFileCopy.m b/fcn_help/createFileCopy.m deleted file mode 100644 index 4bf198e..0000000 --- a/fcn_help/createFileCopy.m +++ /dev/null @@ -1,52 +0,0 @@ -function [] = createFileCopy(filePaths,folderName,storPath,ID,type) -% Creates a copy of the files (can be used for multiple paths in a cell array) -% folderName is the name of the exporting folder - disp(['start to copy ', type]); - - if ~iscell(filePaths) - %fixes Issue if Filepath is a char and not a cell array - filePaths = {filePaths}; - end - - try - for i = 1:numel(filePaths) - FileNameAndLocation = filePaths{i}; - [~,name,ext] = fileparts(filePaths{i}); % get the extension - - switch type - case 'data' - sufix = '_data'; - newfile = sprintf([ID, sufix, '_' , num2str(i) ,ext]); - case 'dataCentral' - %keep original name - newfile = sprintf([name,ext]); - case 'script' - sufix = '_script'; - newfile = sprintf([ID, sufix ,ext]); - case 'userFcn' - %keep original name - newfile = sprintf([name,ext]); - otherwise - error([type,' is not a valid type for createFileCopy']) - end %switch - - % Write the file - RemotePath = fullfile(storPath,folderName, newfile); - -% Check if remote file already exists - count = 0; - while isfile(RemotePath) && ismember(type,{'data','dataCentral'}) - % Add a Sufix number to new file name - count = count + 1; - [~,name,ext] = fileparts(RemotePath); - RemotePath = fullfile(storPath,folderName,... - [name,'_',num2str(count),ext]); - end - copyfile(FileNameAndLocation,RemotePath); - end - disp([type, ' sucessfully published']); - catch - warning([type,' export was not sucessful']) - end %try -end - diff --git a/fcn_help/createLinkedHDF5.m b/fcn_help/createLinkedHDF5.m deleted file mode 100644 index 2738fd1..0000000 --- a/fcn_help/createLinkedHDF5.m +++ /dev/null @@ -1,20 +0,0 @@ -function [status] = createLinkedHDF5(SourceFile,TargetPath,ID) -%createLinkedHDF5 creates a HDF file that references the Sourcefile -% TargetPath is the storage location, ID the foldername -% Status returns true if the function was sucessfull - -plist_id = 'H5P_DEFAULT'; - -% try - fid = H5F.create(fullfile(TargetPath,ID,[ID,'_data.h5'])); - %create External Link to Sourcefile in the Group linkToExternal - H5L.create_external(['..\data\',SourceFile],'/',fid, SourceFile ,plist_id,plist_id); - H5F.close(fid); - status = 1; -% catch -% warning('No linked HDF file was created'); -% status = 0; -% end - -end - diff --git a/fcn_help/fileCompare.m b/fcn_help/fileCompare.m deleted file mode 100644 index c9007e7..0000000 --- a/fcn_help/fileCompare.m +++ /dev/null @@ -1,49 +0,0 @@ -function [status, id] = fileCompare(filename,fileList) -%fileCompare checks if file1 is (binary) identical to a file in filelist -% it returns a sttus and the id of the identical file -% the functions uses the windows system function fc or the unix function -% diff - -if isempty(fileList) - % no comparison necessary - status =false; - id = 0; - return -end - -[~,~,ext1] = fileparts(filename); -id = zeros(height(fileList),1); - -for i=1:height(fileList) - [~,~,ext2] = fileparts(fileList.name{i}); - - if ~isequal(ext1,ext2) - %warning('File extension are not identical'); - status = false; - continue - end - - filepath = fullfile(fileList.folder{i},fileList.name{i}); - if ispc - [status,~] = system(['fc ' filename ' ' filepath]); - % 0 -> identical, 1 -> not identical - status = ~status; % false (not identical), true(identical) - - elseif isunix %untested! - [status,~] = system(['diff ' filename ' ' filepath]); - else - warning('Platform not supported') - end - - if status == 1 - id(i) = 1; - else - % Status can also be any other number e.g. 2 - id(i) = 0; - end - - id =logical(id); %bugfix -end - -end - -- GitLab