function [value] = m2tcustom(handle, varargin) % M2TCUSTOM creates user-defined options for matlab2tikz output % % M2TCUSTOM can be used to create, get and set a properly formatted data % structure to customize the conversion of MATLAB figures to TikZ using % matlab2tikz. In particular, it allows to: % % * add blocks of LaTeX/TikZ code around any HG object, % * add blocks of comments around any HG object, % * add TikZ options to any HG object, % * add LaTeX/TikZ code inside some HG objects (e.g. axes), % * provide a custom handler to convert a particular HG object. % % Note that this provides advanced functionality. Only very basic % sanity checks are performed such that injudicious use may produce % broken TikZ figures! % % It is HIGHLY recommended that you are comfortable with: % % * writing pgfplots, TikZ and LaTeX code, % * using the Handle Graphics (HG) framework in MATLAB/Octave, and % * the inner working of matlab2tikz (for custom handlers) % % when you use this function. I.e. you should know what you are doing. % % % Usage as a GETTER: % ------------------ % % value = M2TCUSTOM(handle) % retrieves the current custom data structure from the HG object "handle" % % % Usage as a SETTER: % ------------------ % % M2TCUSTOM(handle, ...) % value = M2TCUSTOM(handle, ...) % will construct the proper data structure and try to set it to the object % |handle| if possible. The arguments (see below) are specified in % key-value pairs akin to a normal |struct|, but here we do a few checks % and data normalization. % % If we denote BLOCK to mean either a |char| or a |cellstr|, the following % options can be passed. Different entries in a cellstr are assumed % separated by a newline. The default values are empty. % % M2TCUSTOM(handle, 'commentBefore', BLOCK, ...) % M2TCUSTOM(handle, 'commentAfter' , BLOCK, ...) % to add comments before/after the object. Our code translates newlines % and adds the percentage signs for you. % % M2TCUSTOM(handle, 'codeBefore', BLOCK, ...) % M2TCUSTOM(handle, 'codeAfter', BLOCK, ...) % M2TCUSTOM(handle, 'codeInsideFirst', BLOCK, ...) % M2TCUSTOM(handle, 'codeInsideLast', BLOCK, ...) % to add raw LaTeX/TikZ code respectively before, after, as first thing % inside or as last thing inside the pgfplots representation of the object. % Note that for some HG objects, (e.g. line objects), |codeInsideFirst| % and |codeInsideLast| do not make any sense and are hence ignored. % % M2TCUSTOM(handle, 'extraOptions', OPTIONS, ...) % adds extra pgfplots/TikZ options to the end of the option list. Here, % OPTIONS is properly formatted TikZ code in % - a |char| (e.g. 'color=red, line width=1pt' ) % - a |cellstr| (e.g. {'color=red','line width=1pt'}) % % M2TCUSTOM(handle, 'customHandler', FUNCTION_HANDLE, ...) % allows you to replace the default matlab2tikz handler for this object. % This is not for the faint of heart and requires intimate knowledge of % the matlab2tikz code base! We expect a function (either as |char| or % function handle) that will be called as % % [m2t, str] = feval(handler, m2t, handle, custom) % % such that the expected function signature is: % % function [m2t, str] = handler(m2t, handle, custom) % % where |m2t| is an undocumented/unstable data structure, % |str| is a char containing TikZ code representing the % HG object |handle| as generated by your handler, % |custom| is a structure as returned by |m2tcustom| % from which you only need to handle |extraOptions|, % |codeInsideFirst| and |codeInsideLast| when applicable. % A particularly useful value for |customHandler| is 'drawNothing', % which remove the object from the output. % % % Example: % -------- % % Executing the following MATLAB code fragment: % % figure; % plot(1:10); % EOL = sprintf('\n'); % m2tCustom(gca, 'codeBefore' , ['' EOL] , ... % 'codeAfter' , ['' EOL] , ... % 'commentsBefore' , '' , ... % 'commentsAfter' , '' , ... % 'codeInsideFirst' , ['' EOL], ... % 'codeInsideLast' , ['' EOL], ... % 'extraOptions' , ''); % % matlab2tikz('test.tikz') % % Should result in a |test.tikz| file with contents that look somewhat % like this: % % \begin{tikzpicture} % % % % \begin{axis}[..., ] % % \addplot{...}; % % \end{axis} % % % % \end{tikzpicture} % % See also: matlab2tikz, setappdata, getappdata %% arguments specific to this constructor function ipp = m2tInputParser(); ipp = ipp.addRequired(ipp, 'handle', @isHgObject); %% Declaration of the custom data structure ipp = ipp.addParamValue(ipp, 'codeBefore', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'codeAfter', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'commentsBefore', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'commentsAfter', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'codeInsideFirst', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'codeInsideLast', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'extraOptions', '', @isCellstrOrChar); ipp = ipp.addParamValue(ipp, 'customHandler', '', @isHandler); %% Parse the arguments ipp = ipp.parse(ipp, handle, varargin{:}); %% Construct custom data structure % We leverage the results from the input parser. It provides us % with validation already. We just need to remove bookkeeping fields value = ipp.Results; value = rmfield(value, {'handle'}); %% Normalize the actual values value.codeBefore = cellstr2char(value.codeBefore); value.codeAfter = cellstr2char(value.codeAfter); value.codeInsideFirst = cellstr2char(value.codeInsideFirst); value.codeInsideLast = cellstr2char(value.codeInsideLast); value.commentsBefore = cellstr2char(value.commentsBefore); value.commentsAfter = cellstr2char(value.commentsAfter); if isempty(value.customHandler) value = rmfield(value, 'customHandler'); end % extraOptions gets normalized by |opts_append_userdefined| %% Different Usage modes MATLAB2TIKZ = 'matlab2tikz'; % key used for application data storage if numel(varargin) == 0 %% GETTER MODE % syntax: value = m2tcustom(h); if ~isempty(handle) object = getappdata(handle, MATLAB2TIKZ); else object = []; end if ~isempty(object) value = object; else % |value| contains all default (empty) values end else %% SETTER MODE % syntax: m2tcustom(h , key1, val1, ...) % syntax: value = m2tcustom([], key1, val1, ...) if ~isempty(handle) setappdata(handle, MATLAB2TIKZ, value); end end end % == INPUT VALIDATORS ========================================================== function bool = isHgObject(value) % true for HG object or empty (or numeric for backwards compatibility) bool = isempty(value) || ishghandle(value) || isnumeric(value); end function bool = isCellstrOrChar(value) % true for cellstr or char bool = ischar(value) || iscellstr(value); end function bool = isHandler(value) % true for char or function handle of the form [m2t, str] = f(m2t, h, opts) bool = isempty(value) || ischar(value) || ... (isa(value, 'function_handle') && ... atLeastOrUnknown(nargin(value), 3) && ... atLeastOrUnknown(nargout(value), 2)); end function bool = atLeastOrUnknown(nargs, limit) % checks for |nargin| and |nargout| >= |limit| (or equal to -1) UNKNOWN = -1; bool = (nargs == UNKNOWN) || nargs >= limit; end % == FIELD NORMALIZATION ======================================================= function value = cellstr2char(value) % convert cellstr to char (and keep char unaffected) if iscellstr(value) EOL = sprintf('\n'); value = m2tstrjoin(value, EOL); end end % ==============================================================================