diff --git a/+PlotID/@config/config.m b/+PlotID/@config/config.m deleted file mode 100644 index e5366246dc0adb85837b6038864a26f72ec6fbd8..0000000000000000000000000000000000000000 --- a/+PlotID/@config/config.m +++ /dev/null @@ -1,78 +0,0 @@ -classdef config < handle - %CONFIG class handles methoths and attributes related to the config - %file - % Detailed explanation goes here - % handle class used for dynamicy property updates - - properties (SetAccess = private) - mandatoryFields = {'Author', 'ProjectID'} - optionFields - end - - properties (SetAccess = protected) - configData - configFileName - end - - methods - function obj = config(configFileName) - %CONFIG Construct an instance of this class - % Detailed explanation goes here - obj.configFileName = configFileName; - try - txt = fileread(obj.configFileName); - obj.configData = jsondecode(txt); - assert(checkConfig(obj)); - - catch - msg = ['no valid config File with the filename ',... - obj.configFileName, ' found.' newline,... - 'Please enter the required information manually']; - disp(msg); - obj.configData = obj.wizard('initilise'); - m = input('Do you want to save the config, Y/N [Y]:','s'); - if ismember(m,{'Y','y'}) - obj.writeConfig(fullfile(pwd)); - end - end%try - - end - - function outputArg = checkConfig(obj) - %checkConfig validates the config file - % 1. Check if mandatory Fields are set - check = isfield(obj.configData,obj.mandatoryFields); - outputArg = all(check); - - end - - function writeConfig(obj,path) - %writeConfig writes the config file to path - % TODo; - fid = fopen(fullfile(path,obj.configFileName),'w'); - txt = jsonencode(obj.configData,'PrettyPrint',true); - %fprintf does not write paths correctly !!! - fwrite(fid,txt); - fclose(fid); - end - - function configData = addPublishOptions(obj,mode) - %writeConfig writes the config file to path - % TODo; - obj.configData.options = obj.plotID_options(mode); - end - - function outputArg = method1(obj,inputArg) - %METHOD1 Summary of this method goes here - % Detailed explanation goes here - outputArg = obj.Property1 + inputArg; - end - - end - - methods (Static) - configStruct = wizard(mode) - optionStruct = plotID_options(input) - end -end - diff --git a/+PlotID/@config/plotID_options.m b/+PlotID/@config/plotID_options.m deleted file mode 100644 index 235f1cb791ef0484873d32a2883aae5daf387406..0000000000000000000000000000000000000000 --- a/+PlotID/@config/plotID_options.m +++ /dev/null @@ -1,28 +0,0 @@ -function [options] = plotID_options(input) -%PLOTID_OPTIONS Summary of this function goes here -% Detailed explanation goes here - -options = struct(); -switch input - case 'default' %same as Arguments Block - options.Location = 'local'; % storage path - options.Method = 'individual'; - options.ParentFolder = 'export'; - options.ConfigFileName = 'config.json';%individual config names possible - options.CopyUserFCN = true; - options.CSV = false; - options.ShowMessages = true; - options.ForcePublish = false; %publish anyway - case 'debug' - options.Location = 'local'; % storage path - options.Method = 'individual'; - options.ParentFolder = 'export'; - options.ConfigFileName = 'config.json';%individual config names possible - options.CopyUserFCN = true; - options.CSV = true; - options.ShowMessages = true; - options.ForcePublish = true; %publish anyway -end - -end - diff --git a/+PlotID/@config/wizard.m b/+PlotID/@config/wizard.m deleted file mode 100644 index de66181d95c25c8d3efa4d06e2e693c28f8bdfbc..0000000000000000000000000000000000000000 --- a/+PlotID/@config/wizard.m +++ /dev/null @@ -1,39 +0,0 @@ -function config = wizard(mode) -%wizard creates config files depending on the selected mode -% initilise ask only for the input that is neccessary to run plotID - -config = struct(); -switch mode - case 'initilise' - config.Author = inputRequired('your Name'); - config.ProjectID = inputRequired('your Project Number'); - - msg = ['Do you want to add a remote path?' newline,... - 'Otherwise your files will be stored locally.' newline,... - 'You can add this later by rerunning the initilisation.']; - disp(msg); - m = input('Do you want add a remothe path, Y/N [Y]:','s'); - - if ismember(m,{'Y','y'}) - config.ServerPath = uigetdir(); - end - otherwise - error('wizard mode undefined in CLASS config'); -end %switch - -end - -function usrTxt = inputRequired(msg) -%Input Dialog that repeats if left empty -inputRequired = true; -while inputRequired - prompt = ['Please enter ', msg , ':']; - inpt = input(prompt,'s'); - if isempty(inpt) - disp('Input must not be empty!'); - else - usrTxt = inpt; - inputRequired = false; - end -end -end \ No newline at end of file diff --git a/+PlotID/@userDLG/userDLG.m b/+PlotID/@userDLG/userDLG.m deleted file mode 100644 index 3ec2b4b9f2af8d2833631b67a52cf9d0f1c1a8a0..0000000000000000000000000000000000000000 --- a/+PlotID/@userDLG/userDLG.m +++ /dev/null @@ -1,80 +0,0 @@ -classdef userDLG - %userDLG the userDLG Class is responsible for the user dialog - % error handeling, user messages and warnings will be provided from - % this class, depending on the user options and error type. - % This reduces messaging overhead and code length in PlotID.Publish() - - properties - configError = false - scriptPublished = false - rdFilesPublished = false - figurePublished = false - msg = '' - end - - properties (SetAccess = protected) - success = false - showMessages {mustBeNumericOrLogical} - forcePublish {mustBeNumericOrLogical} - ID %plotID - end - - methods - function obj = userDLG(ID,options) - %CATCHERROR Construct an instance of this class - if isempty(ID) - ID = ''; - end - obj.ID = ID; - obj.showMessages = options.ShowMessages; - obj.forcePublish = options.ForcePublish; - end - - function output = get.success(obj) - % checks if all publish operations are true - obj.success = all([obj.scriptPublished; obj.rdFilesPublished;... - obj.figurePublished]); - output = obj.success; - end - - function obj = set.msg(obj,message) - %setmsg Summary of this method goes here - % Detailed explanation goes here - obj.msg = message; - end - - function [] = userMSG(obj,message) - %userMSG user message without priority - % MSG will only be displaye if ShowMessages is true - if obj.showMessages - disp(message); - end - end - - function [] = error(obj,message) - %error handles critical errors - % critical errors will always result in a matlab error - - %ToDO: Add function(s) before termination - error(message); - end - - function [] = softError(obj,message) - %softError handles soft errors - % soft errors can be changed to warning if ForcePublish is - % selected by the user - if obj.forcePublish - warning(message); - else - error(message); - end - end - - function outputArg = method1(obj,inputArg) - %METHOD1 Summary of this method goes here - % Detailed explanation goes here - outputArg = obj.Property1 + inputArg; - end - end -end - diff --git a/+PlotID/Publish.m b/+PlotID/Publish.m index 231c185ab862f4e32daa5c97a263f1a49a5c1e02..79ecc2b1799132e3890d2924bf90ec8b46a64d01 100644 --- a/+PlotID/Publish.m +++ b/+PlotID/Publish.m @@ -1,13 +1,5 @@ -function Publish(DataPaths,scriptPath, figure, options) -%%Publish(DataPaths,scriptPath, ID, figure, options) saves plot, data and measuring script -% -% DataPaths contains the path(s) to the research data, for multiple files -% use a cell array -% scriptPath contains the path to the script, this can be provided with -% the simple call of scriptPath = [mfilename('fullpath'),'.m'], note that -% the extension is mandatory -% -% Options: +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. @@ -18,31 +10,14 @@ function Publish(DataPaths,scriptPath, figure, options) % path is used, PlotId will use this path a storagePath arguments - DataPaths {mustBeDataPath} % location of the data-file(s) - scriptPath (1,:) {mustBeFile} % location of the matlab script + 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.ConfigFileName (1,:) {mustBeText} = 'config.json' %individual config names possible - options.CopyUserFCN (1,1) {mustBeNumericOrLogical} = true + options.CopyUserFCN (1,1) {mustBeNumericOrLogical} = true options.CSV (1,1) {mustBeNumericOrLogical} = false - options.ShowMessages(1,1) {mustBeNumericOrLogical} = true - options.ForcePublish (1,1) {mustBeNumericOrLogical} = false %publish anyway - -end - -%% argument validation -%catch string and non cell inputs in DataPaths -if ~iscell(DataPaths) - DataPaths = {DataPaths}; %Cell array -end - -for i=1:numel(DataPaths) - if isstring(DataPaths{i}) - % strings will cause problems - DataPaths{i} = char(DataPaths{i}); - end end %catch multiple figures in fig @@ -54,31 +29,18 @@ if numel(figure) > 1 warning(msg); end -%get ID from Figure -ID = figure.Tag; - -if isempty(ID) - % no ID found, User dialog for Folder name - ID = inputdlg(['No ID defined- ' newline,... - 'Please enter a folder name to continue:'],'Please enter a folder name'); - ID = ID{1}; - msg = ['No ID found - consider to use the TagPlot function before ',... - 'you publish ', newline, 'your files will be stored in ' , ID]; - warning(msg); -end - %% read config file -% there is only one config Object (handleClass) -configObj = PlotID.config(options.ConfigFileName); -if isfield(configObj.configData, 'options') - % is working but prune to user errors - options = configObj.configData.options; +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 -% Error and MSG handeling -dlgObj = PlotID.userDLG(ID,options); - - %% storage location switch options.Location case 'local' @@ -86,43 +48,35 @@ switch options.Location storPath = options.ParentFolder; else % use the script path as export path - scriptLocation = fileparts(scriptPath); - storPath = fullfile(scriptLocation,options.ParentFolder); + scriptPath = fileparts(DataPaths.script); + storPath = fullfile(scriptPath,options.ParentFolder); end case 'server' %from config File - if dlgObj.configError - msg = ['Error while reading the config file' newline,... - ' publishing on server not possible']; - dlgObj.error(msg); - end - storPath = config.ServerPath; + storPath = config.ServerPath; case 'manual' %UI storPath = uigetdir(); case 'CI-Test' storPath = fullfile(pwd,'CI_files',options.ParentFolder); end +folderName = char(ID); -folderName = ['.',char(ID)]; %hidden folder - -%% Create data directory +%% Create Data-Directory if isfolder(fullfile(storPath,folderName)) - dlgObj.error(['Folder ',folderName, ' exists - Plot was already published ']); + error(['Folder ',folderName, ' exists - Plot was already published ']); elseif mkdir(fullfile(storPath,folderName)) else - dlgObj.error('Directory could not be created - check remote path and permissions'); + 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) +%% Create a Copy of the script and user functions(optional) % script -[~, status, msg] = PlotID.createFileCopy({scriptPath},folderName,storPath,ID, 'script'); -dlgObj.scriptPublished =status; -dlgObj.userMSG(msg); +PlotID.createFileCopy({[DataPaths.script,'.m']},folderName,storPath,ID, 'script'); % user functions -[fList,pList] = matlab.codetools.requiredFilesAndProducts(scriptPath); +[fList,pList] = matlab.codetools.requiredFilesAndProducts(DataPaths.script); if options.CopyUserFCN - fList = fList(~ismember(fList,scriptPath)); % rmv script from list + 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) @@ -142,16 +96,16 @@ switch options.Method currentPath = fullfile(storPath); %list all files - fList = dir(fullfile(storPath,DataFolderName, ['**',filesep,'*.*'])); + 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) + for i=1:numel(DataPaths.rdata) % check if identical file exists (status = 1) - [~, idx] = PlotID.fileCompare(DataPaths{i},fList); + [~, idx] = PlotID.fileCompare(DataPaths.rdata{i},fList); % create Linked HDF5 files for identical files if any(idx) fList.path = fullfile(fList.folder,fList.name); @@ -159,118 +113,78 @@ switch options.Method relativeSourcePath = strrep(sourcePath,currentPath,''); if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5 - linkedHDFPath = fullfile(storPath,folderName); - PlotID.createLinkedHDF5(relativeSourcePath{1,1},linkedHDFPath); + 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, status, msg] = PlotID.createFileCopy(DataPaths{i},'data',storPath,ID,'dataCentral'); - pathToData = strrep(dataPath,currentPath,''); + [dataPath] = PlotID.createFileCopy(DataPaths.rdata{i},'data',storPath,ID,'dataCentral'); + relativeDataPath = strrep(dataPath,currentPath,''); %WIP - if contains(DataPaths{i},{'.h5','.hdf5'}) % Linking only for HDF5 + if contains(DataPaths.rdata{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); + PlotID.createLinkedHDF5(relativeDataPath,storPath,ID); end %if end %if end %for clear DataFolderName case 'individual' % Create a copy of the research data - [~, status, msg] = PlotID.createFileCopy(DataPaths,folderName,storPath,ID, 'data'); + PlotID.createFileCopy(DataPaths.rdata,folderName,storPath,ID, 'data'); end -%temporary: -dlgObj.rdFilesPublished = status; -dlgObj.userMSG(msg); - %% Write Config File -exportPath = fullfile(storPath,folderName); -configObj.writeConfig(exportPath); -% add further Metadata -meta =struct(); -if ispc - meta.author = getenv('USERNAME'); +if ~configError %config File must exist + % copy config file + configPath = PlotID.createFileCopy('config.json',folderName,... + storPath,ID, 'data'); +else + configPath = fullfile(storPath,folderName,'config.json'); + config = struct(); + if ispc + config.author = getenv('USERNAME'); + end end -meta.ProjectID = ID; -meta.CreationDate = datestr(now); -meta.MatlabVersion = version; -meta.ToolboxVersions = pList; - -% write meta -metaPath = fullfile(storPath,folderName,'plotID_data.json'); -fid = fopen(char(metaPath),'w'); -txt = jsonencode(meta,'PrettyPrint',true); +% 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); - dlgObj.figurePublished = true; + 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 - dlgObj.softError('Plot export was not successful'); + warning('Plot export was not successful') end +disp(['publishing of ', ID , ' done']); + % CSV EXport if options.CSV T = table(); - T.research_Data = DataPaths'; T.PlotID(:) = {ID}; - T.Script_Name(:) = {scriptPath}; + 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 -%% final renaming and error/warning handeling -% if no error orcurred or if force publish is activated, rename the hidden -% folder to a non hidden one, otherwise delete it. -if dlgObj.success || options.ForcePublish - oldPath = fullfile(storPath,folderName); - newPath = strrep(oldPath,'.',''); %remov dot - status = movefile(oldPath,newPath); %rename directory -else - % error from userDlg class! -end - -if status - disp(['publishing of ', ID , ' done']); %always displayed onsucess -else % publish was not sucessfull! - %replace with error from userDLG Class - dlgObj.error(['publishing of ', ID , ' failed']) -end - - end %function -%% Argument Validation Functions function tf = mustBeFigure(h) %checks if input is a figure object tf = strcmp(get(h, 'type'), 'figure') & isa(h, 'matlab.ui.Figure'); 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 - diff --git a/+PlotID/TagPlot.m b/+PlotID/TagPlot.m index b925379f4a5a8a23f5b37d802d0edc61eda0bf4f..4a5965803f3f57eb5de1da8fce1ed84d070c5a0e 100644 --- a/+PlotID/TagPlot.m +++ b/+PlotID/TagPlot.m @@ -14,42 +14,43 @@ function [figs, IDs] = TagPlot(figs, options) arguments figs (1,:) {mustBeFigure} options.ProjectID (1,:) {mustBeText}= '' - options.Fontsize (1,1) {mustBeInteger} = 8 - options.Color (1,3) {mustBeNonnegative} = 0.65*[1 1 1] % grey + options.Fontsize (1,1) {mustBeInteger} = 8 options.Location (1,:) {mustBeText} = 'east' - options.DistanceToAxis {mustBeReal} = .01 % relative distance options.Position (1,2) {mustBeVector} = [1,0.4] % default for east - options.Rotation (1,1) {mustBeReal} = NaN - options.ConfigFileName (1,:) {mustBeText} = 'config.json' + options.Rotation (1,1) {mustBeInteger} = 0 end if isempty(options.ProjectID) - configObj = PlotID.config(options.ConfigFileName); - configData = configObj.configData; - options.ProjectID = configData.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 case 'north' - y = 1 - options.DistanceToAxis - options.Position = [0.4,y]; - Rotation = 0; + options.Position = [0.4,0.95]; + options.Rotation = 0; case 'east' - x = 1 - options.DistanceToAxis; - options.Position = [x,0.4]; - Rotation = 90; + options.Position = [1,0.4]; + options.Rotation = 90; case 'south' - y = 0 + options.DistanceToAxis; - options.Position = [0.4,y]; - Rotation = 0; + options.Position = [0.4,.02]; + options.Rotation = 0; case 'west' - x = 0 + options.DistanceToAxis; - options.Position = [x,0.4]; - Rotation = 90; - case 'southeast' - y = 0 + options.DistanceToAxis; - options.Position = [0.8, y]; - Rotation = 0; + options.Position = [.05,0.4]; + options.Rotation = 90; case 'custom' % Check if Position is valid if ~all(0 <= options.Position & options.Position <= 1) @@ -61,10 +62,6 @@ switch options.Location options.Location = 'east'; options.Position = [1,0.4]; end -if ~isnan(options.Rotation) - Rotation = options.Rotation; -end - IDs = cell(numel(figs),1); for n = 1:numel(figs) @@ -75,11 +72,10 @@ for n = 1:numel(figs) ylim =get(axes,'YLim'); xlim =get(axes,'XLim'); %ID - - position = [options.Position(1), options.Position(2)]; + position = [options.Position(1)*xlim(2), options.Position(2)*ylim(2)]; text(axes,position(1),position(2), IDs{n},'Fontsize',options.Fontsize,... - 'Rotation',Rotation, 'VerticalAlignment','bottom','Color',... - options.Color,'BackgroundColor','w', 'Units', 'normalized'); + 'Rotation',options.Rotation, 'VerticalAlignment','bottom','Color',... + 0.65*[1 1 1],'BackgroundColor','w'); set(figs(n),'Tag', IDs{n}); end diff --git a/+PlotID/createFileCopy.m b/+PlotID/createFileCopy.m index 03e394c2000633f015a48a9340889275dec54549..061f10903343ccde4ea33ea666f93b19f414cb79 100644 --- a/+PlotID/createFileCopy.m +++ b/+PlotID/createFileCopy.m @@ -1,4 +1,4 @@ -function [storagePaths, status, msg] = createFileCopy(filePaths,folderName,storPath,ID,type) +function [storagePaths] = 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 % returns the storage paths were files were stored @@ -68,10 +68,8 @@ try copyfile(FileNameAndLocation,RemotePath); storagePaths{i} = RemotePath; end - status = true; - msg =([type, ' successfully published']); + disp([type, ' sucessfully published']); catch - status = false; warning([type,' export was not sucessful']) if exist('errorMSG') error(errorMSG); diff --git a/+PlotID/createLinkedHDF5.m b/+PlotID/createLinkedHDF5.m index 8807977d929aed8af169a866c4ba4aa329fda8d4..8fecfaed42b86014895c16a9bdd9a03eb554bec5 100644 --- a/+PlotID/createLinkedHDF5.m +++ b/+PlotID/createLinkedHDF5.m @@ -1,4 +1,4 @@ -function [status] = createLinkedHDF5(SourceFile,TargetPath) +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 @@ -16,12 +16,12 @@ end %old %fid = H5F.create(fullfile(TargetPath,ID,[ID,'_data.h5'])); - fid = H5F.create(fullfile(TargetPath,[filename,ext])); + 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(['..',filesep,'data',filesep,SourceFile],'/',fid, SourceFile ,plist_id,plist_id); %original + 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,[filename,ext]),' created']); + disp([fullfile(TargetPath,ID,[filename,ext]),' created']); status = 1; % catch % warning('No linked HDF file was created'); diff --git a/+PlotID/initilise.m b/+PlotID/initilise.m deleted file mode 100644 index 4f893441299d085fa8f5a06fbd4dc36b105df04c..0000000000000000000000000000000000000000 --- a/+PlotID/initilise.m +++ /dev/null @@ -1,7 +0,0 @@ -function [status] = initilise() -%INITILISE Initilisation for first time úsage - - - -end - diff --git a/+PlotID/removePltIdFiles.m b/+PlotID/removePltIdFiles.m index 169990d0f7e6f6d99b73f1b5d91c8454b9cf9a65..37ef1827ad2049bd261780e4d190f05907a7b676 100644 --- a/+PlotID/removePltIdFiles.m +++ b/+PlotID/removePltIdFiles.m @@ -1,26 +1,19 @@ function [fListClean] = removePltIdFiles(fList) %removePltIdFiles removes functions that are part of PlotID out of flist % Detailed explanation goes here +%addpath('..\fcn_core'); [~,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; +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'),:); -% 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)); +fListClean = fList(~ismember(names,PltID_flist.name)); + end diff --git a/.gitignore b/.gitignore index 32ea2493881e83b59a61c69dbd6ba01281a72d3b..708bea6b2032d70640c74a197d183a115ff0bdda 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,6 @@ testdata_2.h5 testdata2.h5 test_data.mat export/* -unused*/* # Octave session info octave-workspace diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 938d8bc80d5bdeff95757803ef2d80a778269d1e..7901609ef3b830a97e409b23c51890ace703b737 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,16 +5,6 @@ Test Code: stage: Run tags: - matlab - - bash script: - - cd ./CI_files - - chmod +x ./runner_linux.sh - - ./runner_linux.sh - - cat ./log.txt - artifacts: - paths: - - ./CI_files/log.txt - - ./CI_files/matlab_log.txt - - when: always - expire_in: 1 week + - ./CI_files/runtest.ps1 + - cat log2.txt diff --git a/CITATION.cff b/CITATION.cff deleted file mode 100644 index 6c8e17a380a65867c2de3888abcc23f8d09d4f8f..0000000000000000000000000000000000000000 --- a/CITATION.cff +++ /dev/null @@ -1,18 +0,0 @@ -cff-version: 1.2.0 -title: >- - plotID a toolkit for connecting research data and - figures -message: >- - developed at the Chair of Fluid System, Techische - Universität Darmstadt within the framework of the NFDI4Ing consortium Funded by the German Research Foundation (DFG) - project number 442146713 -type: software -authors: - - given-names: Jan - family-names: Lemmer - email: jan.lemmer@fst.tu-darmstadt.de - affiliation: 'Chair of Fluid Systems, TU Darmstadt' - orcid: 'https://orcid.org/0000-0002-0638-1567' - - given-names: Martin - family-names: Hock - email: martin.hock@fst.tu-darmstadt.de - affiliation: 'Chair of Fluid Systems, TU Darmstadt' diff --git a/CI_files/default_test.m b/CI_files/default_test.m index f6c7309d399deaa2453cf51045d5970073da8ba8..505c360ea8fde4390434772eeece053120d15f0e 100644 --- a/CI_files/default_test.m +++ b/CI_files/default_test.m @@ -1,126 +1,72 @@ function [result] = default_test() -%default_test() This is a simple test if Plot ID works for the default settings +%UNTITLED2 This is a simple test if Plot ID works for the default settings % Detailed explanation goes here clear; clc; close all; -% set path -% starting path of gitlab runner is in CI_files -if contains(pwd,'CI_files') - cd .. % move one directory up -end - -addpath('CI_files'); - % clean up, if previous run failed try - delete(['CI_files' filesep 'export' filesep '*']); - delete(['CI_files' filesep '*.mat']); - delete(['CI_files' filesep '*.h5']); - rmdir(['CI_files' filesep 'export'],'s'); + delete CI_files/export/* CI_files/*.mat CI_files/*.h5 + rmdir('CI_files/export','s'); end -% initialise -numberOfTests = 2; -testResults = zeros(numberOfTests,1); - -%start log -fid = fopen(fullfile('CI_files','log.txt'),'w'); -txt = ['default test started ' newline]; -fprintf(fid,txt); - -% create Config for CI-Tests -fid1 = fopen(fullfile('CI_files','CI_config.json'),'w'); -configData.Author = 'CI-Test'; configData.ProjectID = 'CI-001'; -txt = jsonencode(configData,'PrettyPrint',true); -%fprintf does not write paths correctly !!! -fwrite(fid1,txt); -fclose(fid1); - -try - ProjectID = 'Test01'; - %% Data - % some random data - x = linspace(0,7); - y = rand(1,100)+2; - dataset1 = fullfile('CI_files','test_data.mat'); - save(dataset1,'x','y'); - % some data as .h5 - x1 = linspace(0,2*pi); - y1 = sin(x1)+2; - - % define file path & name - fpath = fullfile("CI_files","testdata2.h5"); - dataset2 = fullfile('CI_files','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 - - fig(1) =figure('visible','off'); - plot(x,y,'-k'); - hold on - plot(x1,y1,'-r'); - msg = 'simple_test succeed stage 1'; -catch - testResults(1) = 1; %test fails - msg = 'simple_test failed in Stage 1'; - warning(msg); -end - -fprintf(fid,[msg newline]); +ProjectID = 'Test01'; +%% Data +% some random data +x = linspace(0,7); +y = rand(1,100)+2; +dataset1 = 'test_data.mat'; +save('CI_files/test_data.mat','x','y'); +% some data as .h5 +x1 = linspace(0,2*pi); +y1 = sin(x1)+2; + +% define file path & name +fpath = "CI_files/testdata_2.h5"; +dataset2 = 'testdata_2.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 + +fig(1) =figure('visible','off'); +plot(x,y,'-k'); +hold on +plot(x1,y1,'-r'); %% Tag the plot try - [figs, ID] = PlotID.TagPlot(fig,'ConfigFileName', 'CI_config.json'); + [figs, ID] = PlotID.TagPlot(fig,'ProjectID', ProjectID); %% call a dummy function - %a=1; - %a = example_fcn(a); + a=1; + a = example_fcn(a); %% publishing % The functions needs the file location, the location of the data and the % figure - script = [mfilename('fullpath'),'.m']; % filename of the m.script + path.script = mfilename('fullpath'); % filename of the m.script % file name of the data - rdata = {dataset1,dataset2} ; % don't forget the extension + path.rdata = {dataset1,dataset2} ; % don't forget the extension - PlotID.Publish(rdata,script, figs, 'Location', 'CI-Test',... - 'ConfigFileName', 'CI_config.json'); + PlotID.Publish(path, ID, figs, 'Location', 'CI-Test') + result = true; - msg = 'simple_test succeed Stage 2'; - + % clean up + delete CI_files/export/* CI_files/*.mat CI_files/*.h5 + rmdir('CI_files/export','s'); + + clear; clc; + catch - testResults(2) = 1; %fail - msg = 'simple_test failed in Stage 2'; - warning(msg); -end -fprintf(fid,[msg newline]); %log - -%% Test result -if any(testResults) - result = 1; %fail - warning('test failed'); -else - result = 0; % pass - disp('test succeed'); -end - -fclose(fid); - -% final clean up -try - delete(['CI_files' filesep 'export' filesep '*']); - delete(['CI_files' filesep '*.mat']); - delete(['CI_files' filesep '*.h5']); - rmdir(['CI_files' filesep 'export'],'s'); - delete(fullfile('CI_files','CI_config.json')); + result = false; + warning('simple_test failed'); end end diff --git a/CI_files/fail_runner.m b/CI_files/fail_runner.m deleted file mode 100644 index e9071dd65411802d16b925aca9ca35c5df933ea4..0000000000000000000000000000000000000000 --- a/CI_files/fail_runner.m +++ /dev/null @@ -1,8 +0,0 @@ -function [retVal] = fail_runner() -%RUNNER_TESTING testing function to test, if the runner is set up properly - retVal = 1; % test should fail ! - fid = fopen(fullfile('log.txt'),'w'); - txt = ['This is a test, Errorstate: ', num2str(retVal)]; - fprintf(fid,txt); - fclose(fid); -end diff --git a/CI_files/pass_runner.m b/CI_files/pass_runner.m deleted file mode 100644 index 957268576f9bd1f4bdc89fb2cbcb69428d8cd229..0000000000000000000000000000000000000000 --- a/CI_files/pass_runner.m +++ /dev/null @@ -1,8 +0,0 @@ -function [retVal] = pass_runner() -%pass_runner testing function to test, if the runner is set up properly - retVal = 0; % test should succeed ! - fid = fopen(fullfile('log.txt'),'w'); - txt = ['This is a test, Errorstate: ', num2str(retVal)]; - fprintf(fid,txt); - fclose(fid); -end diff --git a/CI_files/runner_linux.sh b/CI_files/runner_linux.sh deleted file mode 100644 index f64784cf471314482b52f05ff6f80a39067a367a..0000000000000000000000000000000000000000 --- a/CI_files/runner_linux.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -#matlab -r "disp(['Current folder: ' pwd])" -matlab $@ -nodisplay -nodesktop -nosplash -logfile matlab_log.txt -r "default_test;exit(ans);" - -exitstatus=$? -if [[ $exitstatus -eq '0' ]] -then - echo "matlab succeed. Exitstatus: $exitstatus" - exit $exitstatus -else - echo "matlab failed. Exitstatus: $exitstatus" - exit $exitstatus - -fi diff --git a/CI_files/runner_test.m b/CI_files/runner_test.m new file mode 100644 index 0000000000000000000000000000000000000000..496afd8558f128e08826f25e62472d6b3cb15f62 --- /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/CI_files/runtest.ps1 b/CI_files/runtest.ps1 deleted file mode 100644 index 15d17374764ae708af434eabcfa372828f527be0..0000000000000000000000000000000000000000 --- a/CI_files/runtest.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -# runtest.ps1 - -$LOGFILE='CI_log.txt' -$wd = pwd; -$LOGFILE = $("$wd" + "\" + "$LOGFILE") -$CIfolder = "$wd" + "\" + "CI_files\" -# $MFILE='"C:\git\NFDI4ing\plot_ID_matlab\CI_files\runner_test.m"' -$arguments = "-nodesktop", "-nosplash","-minimize","-wait","-sd", "$wd", "-logfile", "$LOGFILE","-batch","CI_files\test_runner_STFS.m" -$Returnvalue = & 'C:\Program Files\MATLAB\R2021b\bin\matlab.exe' $arguments - -#$CODE = $? -# Returnvalue doesnt get anything useful from matlab -# Write-Output($Returnvalue) -Write-Output(Get-Content($LOGFILE)) - -exit $CODE - diff --git a/Initialisation.m b/Initialisation.m deleted file mode 100644 index 97835f3364ac842e857a021953fa2f2c632fd38e..0000000000000000000000000000000000000000 --- a/Initialisation.m +++ /dev/null @@ -1,29 +0,0 @@ -%% This is the PlotID Initialisation file -% Please run this script before using PlotID - -%% Step 1: Add plotID location to you MATLAB path -% This is necessary to use PlotID in your personal MATLAB Scripts -addpath(pwd); -savepath; - -%% Section 2 Config File -% To make things easy, you should use the config file. The following wizard -% will help you create one: -writeConfig = true; - -% Ask User if current config should be overwritten -if isfile('config.json') - m = input('Do you want to overwrite the current config file, Y/N [Y]:','s'); - writeConfig = ismember(m,{'Y','y'}); -end - -if writeConfig - config = PlotID.config.wizard('initilise'); - fid = fopen('config.json','w'); - txt = jsonencode(config,'PrettyPrint',true); - fwrite(fid,txt); - fclose(fid); -end - -%% -disp('Initialisition done.') diff --git a/PlotID_Demo.m b/PlotID_Demo.m new file mode 100644 index 0000000000000000000000000000000000000000..766ad17cfb60feb31820c5382e61b6f3cc7d413b --- /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 342cf55fc3bc97c07fcf011bc7ef83f2b9744015..83e88a152b92188d60874df012febdad41e3bce5 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,20 @@ Feel free to give feedback and feature requests or to take part in the developme [TOC] # Quick User Guide -**Requirements:** MATLAB R2021a or newer - `PlotID` works in two Steps: 1. tagging the plot `[figs, IDs] = plotId.TagPlot(figs, options)` -You should either set a ProjectID in the config.json (copy & rename the 'example-config.json' to 'config.json'), or pass it as option 'ProjectID' to the TagPlot function. -2. publish the plot and the associated data -`plotID.Publish(DataPaths,scriptPath, figure, options)` -`scriptPath` contains the path to the script, this can be provided with the simple call of `scriptPath = [mfilename('fullpath'),'.m']`, note that - **the extension is mandatory.** +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` contains the path(s) to the research data, for multiple files you can use a cell arrays (they must be at the path). -`figure` is the figure that should be published. - +`DataPaths.rdata = {dataset1, dataset2};` file names of the datasets (they most be at the path) + +You should either set a ProjectID in the config.json (copy & rename the 'example-config.json' to 'config.json'), or pass it as option 'ProjectID' to the TagPlot function. # PlotID.TagPlot() `[figs, IDs] = TagPlot(figs, options)` @@ -66,7 +63,7 @@ FriendlyID Changes the Hex Number to a human friendly *datetime* and *dateStr*. # PlotID.Publish() -`Publish(DataPaths,scriptPath, figure, options)` \ +`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 diff --git a/example-config.json b/example-config.json new file mode 100644 index 0000000000000000000000000000000000000000..92b8621a1d43e5fc26290fa6acce3be448471d3e --- /dev/null +++ b/example-config.json @@ -0,0 +1,5 @@ +{ + "Author": "Example Author", + "ProjectID": "AB01", + "ServerPath": "\\\\Server\\path\\folder" +} diff --git a/example.m b/example.m index b64044db476204bb46edce6332f08ddb80be7573..04aa8c11aebc102d0810c7e23681ad1ba473d943 100644 --- a/example.m +++ b/example.m @@ -43,8 +43,7 @@ h5write(fpath, "/y1", y1) % 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); -% Uncomment to include the Statistics and Machine learning Toolbox -% p = betacdf(0.5,1,1); % to test toolboxes +p = betacdf(0.5,1,1); % to test toolboxes %% Plotting % This is still part of a normal script to produce plots. @@ -62,24 +61,21 @@ set(gca, 'TickDir', 'out', 'YLim', [0,4]); % 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); -[fig, ID] = PlotID.TagPlot(fig); +[fig, ID] = PlotID.TagPlot(fig, 'ProjectID', ProjectID); + %% Publishing % Second part of plotID % The functions needs the file location of the script, the location of the % data and the figure and can take several options (see readme). -% filename of the m.script, extension must be added! -scriptPath = [mfilename('fullpath'),'.m']; - +path.script = mfilename('fullpath'); % filename of the m.script % file names of the datasets %(defined above:) dataset1 = 'test_data.mat'; dataset2 = 'testdata2.h5' -locations = {dataset1,dataset2} ; % don't forget the extension -locations = {string(dataset1),dataset2}; +path.rdata = {dataset1,dataset2} ; % don't forget the extension %call publishing -PlotID.Publish(locations,scriptPath, fig(1), 'Location', 'local' ,'Method','individual') +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 @@ -94,13 +90,13 @@ set(gca, 'TickDir', 'out', 'YLim', [0,4]); [fig, IDs] = PlotID.TagPlot(fig,'ProjectID', ProjectID); % data locations -script = [mfilename('fullpath'),'.m']; % filename of the m.script +path.script = mfilename('fullpath'); % filename of the m.script % file names of the datasets -rdata = dataset2 ; % don't forget the extension +path.rdata = {dataset2} ; % don't forget the extension % publsihing via a for-loop for i=1: numel(fig) - PlotID.Publish(rdata, script, fig(i), 'Location', 'local',... + PlotID.Publish(path, IDs{i}, fig(i), 'Location', 'local',... 'Method','individual'); end @@ -118,4 +114,4 @@ plot(x1,y1,'-r'); [fig2, ID] = PlotID.TagPlot(fig2,'ProjectID', ProjectID); -PlotID.Publish(locations,scriptPath, fig2, 'Location', 'local','Method','centralized') +PlotID.Publish(path, ID, fig2, 'Location', 'local','Method','centralized')