diff --git a/+PlotID/@userDLG/userDLG.m b/+PlotID/@userDLG/userDLG.m new file mode 100644 index 0000000000000000000000000000000000000000..3ec2b4b9f2af8d2833631b67a52cf9d0f1c1a8a0 --- /dev/null +++ b/+PlotID/@userDLG/userDLG.m @@ -0,0 +1,80 @@ +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 b701698a1685bd6ccc47a4d9ec185a83a40a7c30..34917d3fa655c260fd48827af524c4c0805538e1 100644 --- a/+PlotID/Publish.m +++ b/+PlotID/Publish.m @@ -24,8 +24,12 @@ arguments 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.ConfigFileName (1,:) {mustBeText} = 'config.json' %individual config names possible + 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 @@ -39,8 +43,8 @@ if numel(figure) > 1 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,... @@ -50,18 +54,16 @@ if isempty(ID) 'you publish ', newline, 'your files will be stored in ' , ID]; warning(msg); end - + +% Error and MSG handeling +dlgObj = PlotID.userDLG(ID,options); %% 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; + dlgObj.configError = true; end %% storage location @@ -75,26 +77,34 @@ switch options.Location storPath = fullfile(scriptLocation,options.ParentFolder); end case 'server' %from config File - storPath = config.ServerPath; + if dlgObj.configError + msg = ['Error while reading the config file' newline,... + ' publishing on server not possible']; + dlgObj.error(msg); + end + 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 +folderName = ['.',char(ID)]; %hidden folder + +%% Create data directory if isfolder(fullfile(storPath,folderName)) - error(['Folder ',folderName, ' exists - Plot was already published ']); + dlgObj.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'); + dlgObj.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 -PlotID.createFileCopy({scriptPath},folderName,storPath,ID, 'script'); +[~, status, msg] = PlotID.createFileCopy({scriptPath},folderName,storPath,ID, 'script'); +dlgObj.scriptPublished =status; +dlgObj.userMSG(msg); % user functions [fList,pList] = matlab.codetools.requiredFilesAndProducts(scriptPath); @@ -136,27 +146,32 @@ switch options.Method relativeSourcePath = strrep(sourcePath,currentPath,''); if contains(sourcePath,{'.h5','.hdf5'}) % Linking only for HDF5 - PlotID.createLinkedHDF5(relativeSourcePath{1,1},storPath,ID); + linkedHDFPath = fullfile(storPath,folderName); + PlotID.createLinkedHDF5(relativeSourcePath{1,1},linkedHDFPath); end else % no identical file exists %Copy the file in data and create the links (if hdf5) - [dataPath] = PlotID.createFileCopy(DataPaths{i},'data',storPath,ID,'dataCentral'); - relativeDataPath = strrep(dataPath,currentPath,''); + [dataPath, status, msg] = PlotID.createFileCopy(DataPaths{i},'data',storPath,ID,'dataCentral'); + pathToData = strrep(dataPath,currentPath,''); %WIP if contains(DataPaths{i},{'.h5','.hdf5'}) % Linking only for HDF5 % and create also linked files in the plot folder - PlotID.createLinkedHDF5(relativeDataPath,storPath,ID); + linkedHDFPath = fullfile(storPath,folderName); + [status] = PlotID.createLinkedHDF5(pathToData,linkedHDFPath); end %if end %if end %for clear DataFolderName case 'individual' % Create a copy of the research data - PlotID.createFileCopy(DataPaths,folderName,storPath,ID, 'data'); + [~, status, msg] = PlotID.createFileCopy(DataPaths,folderName,storPath,ID, 'data'); end -%% Write Config File +%temporary: +dlgObj.rdFilesPublished = status; +dlgObj.userMSG(msg); -if ~configError %config File must exist +%% Write Config File +if ~dlgObj.configError %config File must exist % copy config file configPath = PlotID.createFileCopy('config.json',folderName,... storPath,ID, 'data'); @@ -182,18 +197,17 @@ 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); + 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; catch - warning('Plot export was not successful') + dlgObj.softError('Plot export was not successful'); end -disp(['publishing of ', ID , ' done']); - % CSV EXport if options.CSV T = table(); @@ -205,6 +219,25 @@ if options.CSV 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 @@ -216,7 +249,7 @@ end function mustBeDataPath(DataPaths) %checks if input is a valid DataPath object - if iscellstr(DataPaths) + if isstring(DataPaths) tf = zeros(1,numel(DataPaths)); for i=1:numel(DataPaths) tf(i) = ~isfile(DataPaths{i}); diff --git a/+PlotID/TagPlot.m b/+PlotID/TagPlot.m index 4a5965803f3f57eb5de1da8fce1ed84d070c5a0e..c72ae4b416ea807187b940f4eec500adb856e02c 100644 --- a/+PlotID/TagPlot.m +++ b/+PlotID/TagPlot.m @@ -14,10 +14,11 @@ function [figs, IDs] = TagPlot(figs, options) arguments figs (1,:) {mustBeFigure} options.ProjectID (1,:) {mustBeText}= '' - options.Fontsize (1,1) {mustBeInteger} = 8 + options.Fontsize (1,1) {mustBeInteger} = 8 + options.Color (1,3) {mustBeNonnegative} = 0.65*[1 1 1] % grey options.Location (1,:) {mustBeText} = 'east' options.Position (1,2) {mustBeVector} = [1,0.4] % default for east - options.Rotation (1,1) {mustBeInteger} = 0 + options.Rotation (1,1) {mustBeReal} = NaN end if isempty(options.ProjectID) @@ -41,16 +42,19 @@ end switch options.Location case 'north' options.Position = [0.4,0.95]; - options.Rotation = 0; + Rotation = 0; case 'east' options.Position = [1,0.4]; - options.Rotation = 90; + Rotation = 90; case 'south' options.Position = [0.4,.02]; - options.Rotation = 0; + Rotation = 0; case 'west' options.Position = [.05,0.4]; - options.Rotation = 90; + Rotation = 90; + case 'southeast' + options.Position = [0.8,.02]; + Rotation = 0; case 'custom' % Check if Position is valid if ~all(0 <= options.Position & options.Position <= 1) @@ -62,6 +66,10 @@ 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) @@ -72,10 +80,11 @@ for n = 1:numel(figs) ylim =get(axes,'YLim'); xlim =get(axes,'XLim'); %ID - position = [options.Position(1)*xlim(2), options.Position(2)*ylim(2)]; + + position = [options.Position(1), options.Position(2)]; text(axes,position(1),position(2), IDs{n},'Fontsize',options.Fontsize,... - 'Rotation',options.Rotation, 'VerticalAlignment','bottom','Color',... - 0.65*[1 1 1],'BackgroundColor','w'); + 'Rotation',Rotation, 'VerticalAlignment','bottom','Color',... + options.Color,'BackgroundColor','w', 'Units', 'normalized'); set(figs(n),'Tag', IDs{n}); end diff --git a/+PlotID/createFileCopy.m b/+PlotID/createFileCopy.m index 34fc8abc7620737b7684e3be4821441d8e89ee95..03e394c2000633f015a48a9340889275dec54549 100644 --- a/+PlotID/createFileCopy.m +++ b/+PlotID/createFileCopy.m @@ -1,4 +1,4 @@ -function [storagePaths] = createFileCopy(filePaths,folderName,storPath,ID,type) +function [storagePaths, status, msg] = createFileCopy(filePaths,folderName,storPath,ID,type) % Creates a copy of the files (can be used for multiple paths in a cell array) % folderName is the name of the exporting folder % returns the storage paths were files were stored @@ -68,8 +68,10 @@ try copyfile(FileNameAndLocation,RemotePath); storagePaths{i} = RemotePath; end - disp([type, ' successfully published']); + status = true; + msg =([type, ' successfully 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 5a86201469989443a69be6c2f526189ef09a7aae..8807977d929aed8af169a866c4ba4aa329fda8d4 100644 --- a/+PlotID/createLinkedHDF5.m +++ b/+PlotID/createLinkedHDF5.m @@ -1,4 +1,4 @@ -function [status] = createLinkedHDF5(SourceFile,TargetPath,ID) +function [status] = createLinkedHDF5(SourceFile,TargetPath) %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,ID,[filename,ext])); + fid = H5F.create(fullfile(TargetPath,[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 H5F.close(fid); - disp([fullfile(TargetPath,ID,[filename,ext]),' created']); + disp([fullfile(TargetPath,[filename,ext]),' created']); status = 1; % catch % warning('No linked HDF file was created'); diff --git a/+PlotID/removePltIdFiles.m b/+PlotID/removePltIdFiles.m index 7a5703cb492355127dd4b18d8194da9c6d9a2272..942b216565c78516978c4dc507eed7e3e2d1c2c5 100644 --- a/+PlotID/removePltIdFiles.m +++ b/+PlotID/removePltIdFiles.m @@ -7,7 +7,8 @@ names = strcat(names, ext); % add ext for comparison % Get a list of all .m files that are part of Plot id packageContent = what('PlotID'); -PltID_flist = packageContent.m; %get list of files +% packageContent.classes has no extensions +PltID_flist = [packageContent.m; strcat(packageContent.classes,'.m')]; % Comparison and filter fListClean = fList(~ismember(names,PltID_flist)); diff --git a/.gitignore b/.gitignore index 708bea6b2032d70640c74a197d183a115ff0bdda..32ea2493881e83b59a61c69dbd6ba01281a72d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ testdata_2.h5 testdata2.h5 test_data.mat export/* +unused*/* # Octave session info octave-workspace diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000000000000000000000000000000000..6c8e17a380a65867c2de3888abcc23f8d09d4f8f --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,18 @@ +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/example.m b/example.m index de981f8dab90a75f801f7314aafc33d1bfbbb660..6ef682af0953da218e07ae365e3618906d8bcdd9 100644 --- a/example.m +++ b/example.m @@ -43,7 +43,8 @@ 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); -p = betacdf(0.5,1,1); % to test toolboxes +% Uncomment to include the Statistics and Machine learning Toolbox +% p = betacdf(0.5,1,1); % to test toolboxes %% Plotting % This is still part of a normal script to produce plots.