{"id":11088,"date":"2019-10-18T09:00:17","date_gmt":"2019-10-18T13:00:17","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/?p=11088"},"modified":"2019-10-20T20:59:09","modified_gmt":"2019-10-21T00:59:09","slug":"spider-plots-and-more-argument-validation","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2019\/10\/18\/spider-plots-and-more-argument-validation\/","title":{"rendered":"Spider plots and more argument validation"},"content":{"rendered":"\r\n\r\n<div class=\"content\"><p><a href=\"http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/869871\">Jiro<\/a>&#8216;s Pick this week is <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561\"><tt>spider_plot<\/tt><\/a> by <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3279387\">Moses<\/a>.<\/p><p>There are quite a few <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange?sort=date_desc_updated&amp;q=spider+plot\">&#8220;spider plots&#8221;<\/a> on the File Exchange, but this one by Moses caught my attention for a few reasons.<\/p><div><ul><li>Moses includes a detailed help inside the function.<\/li><\/ul><\/div><pre class=\"codeinput\">help <span class=\"string\">spider_plot<\/span>\r\n<\/pre><pre class=\"codeoutput\"> spider_plot Create a spider or radar plot with individual axes.\r\n \r\n  Syntax:\r\n    spider_plot(P)\r\n    spider_plot(___, Name, Value)\r\n \r\n  Input Arguments:\r\n    (Required)\r\n    P                - The data points used to plot the spider chart. The\r\n                       rows are the groups of data and the columns are the\r\n                       data points. The axes labels and axes limits are\r\n                       automatically generated if not specified.\r\n                       [vector | matrix]\r\n \r\n  Name-Value Pair Arguments:\r\n    (Optional)\r\n    AxesLabels       - Used to specify the label each of the axes.\r\n                       [auto-generated (default) | cell of strings | 'none']\r\n \r\n    AxesInterval     - Used to change the number of intervals displayed\r\n                       between the webs.\r\n                       [3 (default) | integer]\r\n \r\n    AxesPrecision    - Used to change the precision level on the value\r\n                       displayed on the axes. Enter in 'none' to remove\r\n                       axes text.\r\n                       [1 (default) | integer | 'none']\r\n \r\n    AxesLimits       - Used to manually set the axes limits. A matrix of\r\n                       2 x size(P, 2). The top row is the minimum axes\r\n                       limits and the bottow row is the maximum axes limits.\r\n                       [auto-scaled (default) | matrix]\r\n \r\n    FillOption       - Used to toggle color fill option.\r\n                       ['off' (default) | 'on']\r\n \r\n    FillTransparency - Used to set color fill transparency.\r\n                       [0.1 (default) | scalar in range (0, 1)]\r\n \r\n    Color            - Used to specify the line color, specified as an RGB\r\n                       triplet. The intensities must be in the range (0, 1).\r\n                       [MATLAB colors (default) | RGB triplet]\r\n \r\n    LineStyle        - Used to change the line style of the plots.\r\n                       ['-' (default) | '--' | ':' | '-.' | 'none']\r\n \r\n    LineWidth        - Used to change the line width, where 1 point is \r\n                       1\/72 of an inch.\r\n                       [0.5 (default) | positive value]\r\n \r\n    Marker           - Used to change the marker symbol of the plots.\r\n                       ['o' (default) | 'none' | '*' | 's' | 'd' | ...]\r\n \r\n    MarkerSize       - Used to change the marker size, where 1 point is\r\n                       1\/72 of an inch.\r\n                       [8 (default) | positive value]\r\n \r\n    FontSize         - Used to change the font size of the labels and\r\n                       values displayed on the axes.\r\n                       [10 (default) | scalar value greater than zero]\r\n \r\n  Examples:\r\n    % Example 1: Minimal number of arguments. All non-specified, optional\r\n                 arguments are set to their default values. Axes labels\r\n                 and limits are automatically generated and set.\r\n \r\n    D1 = [5 3 9 1 2];   % Initialize data points\r\n    D2 = [5 8 7 2 9];\r\n    D3 = [8 2 1 4 6];\r\n    P = [D1; D2; D3];\r\n    spider_plot(P);\r\n    legend('D1', 'D2', 'D3', 'Location', 'southoutside');\r\n  \r\n    % Example 2: Manually setting the axes limits. All non-specified,\r\n                 optional arguments are set to their default values.\r\n \r\n    axes_limits = [1, 2, 1, 1, 1; 10, 8, 9, 5, 10]; % Axes limits [min axes limits; max axes limits]\r\n    spider_plot(P,...\r\n        'AxesLimits', axes_limits);\r\n  \r\n    % Example 3: Set fill option on. The fill transparency can be adjusted.\r\n \r\n    axes_labels = {'S1', 'S2', 'S3', 'S4', 'S5'}; % Axes properties\r\n    axes_interval = 2;\r\n    fill_option = 'on';\r\n    fill_transparency = 0.1;\r\n    spider_plot(P,...\r\n        'AxesLabels', axes_labels,...\r\n        'AxesInterval', axes_interval,...\r\n        'FillOption', fill_option,...\r\n        'FillTransparency', fill_transparency);\r\n  \r\n    % Example 4: Maximum number of arguments.\r\n \r\n    axes_labels = {'S1', 'S2', 'S3', 'S4', 'S5'}; % Axes properties\r\n    axes_interval = 4;\r\n    axes_precision = 'none';\r\n    axes_limits = [1, 2, 1, 1, 1; 10, 8, 9, 5, 10];\r\n    fill_option = 'on';\r\n    fill_transparency = 0.2;\r\n    colors = [1, 0, 0; 0, 1, 0; 0, 0, 1];\r\n    line_style = '--';\r\n    line_width = 3;\r\n    marker_type = 'd';\r\n    marker_size = 10;\r\n    font_size = 12;\r\n    spider_plot(P,...\r\n        'AxesLabels', axes_labels,...\r\n        'AxesInterval', axes_interval,...\r\n        'AxesPrecision', axes_precision,...\r\n        'AxesLimits', axes_limits,...\r\n        'FillOption', fill_option,...\r\n        'FillTransparency', fill_transparency,...\r\n        'Color', colors,...\r\n        'LineStyle', line_style,...\r\n        'LineWidth', line_width,...\r\n        'Marker', marker_type,...\r\n        'MarkerSize', marker_size,...\r\n        'FontSize', font_size);\r\n  \r\n  Author:\r\n    Moses Yoo, (jyoo at hatci dot com)\r\n    2019-10-16: Minor revision to add name-value pairs for customizing\r\n                color, marker, and line settings.\r\n    2019-10-08: Another major revision to convert to name-value pairs and\r\n                add color fill option.\r\n    2019-09-17: Major revision to improve speed, clarity, and functionality\r\n \r\n  Special Thanks:\r\n    Special thanks to Gabriela Andrade &amp; Andr&#65411;&#65385;s Garcia for their\r\n    feature recommendations and suggested bug fixes.\r\n\r\n<\/pre><div><ul><li>He includes a Live Script example that showcases various use cases<\/li><\/ul><\/div><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/pick\/jiro\/potw_spider_plot\/spider_plot_livescript.png\" alt=\"\"> <\/p><div><ul><li>He is very active in his communications with his users in the <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comment\">comments<\/a> section and is also very diligent about updating the entry.<\/li><\/ul><\/div><div><ul><li>And finally, his function is another example where the new <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/function-argument-validation-1.html\">Function Argument Validation<\/a> feature would be handy.<\/li><\/ul><\/div><p>I&#8217;m thrilled to see a nice piece of code with robust error-checking. He has roughly 100 lines of code just for error checking the inputs to his function. He also sets default values for the optional arguments.<\/p><p>Here is the input argument processing\/error checking piece of the code.<\/p><pre class=\"language-matlab\"><span class=\"comment\">%%% Data Properties %%%<\/span>\r\n<span class=\"comment\">% Point properties<\/span>\r\n[num_data_groups, num_data_points] = size(P);\r\n\r\n<span class=\"comment\">% Number of optional arguments<\/span>\r\nnumvarargs = length(varargin);\r\n\r\n<span class=\"comment\">% Check for even number of name-value pair argments<\/span>\r\n<span class=\"keyword\">if<\/span> mod(numvarargs, 2) == 1\r\n    error(<span class=\"string\">'Error: Please check name-value pair arguments'<\/span>);\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Create default labels<\/span>\r\naxes_labels = cell(1, num_data_points);\r\n\r\n<span class=\"comment\">% Iterate through number of data points<\/span>\r\n<span class=\"keyword\">for<\/span> ii = 1:num_data_points\r\n    <span class=\"comment\">% Default axes labels<\/span>\r\n    axes_labels{ii} = sprintf(<span class=\"string\">'Label %i'<\/span>, ii);\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Default arguments<\/span>\r\naxes_interval = 3;\r\naxes_precision = 1;\r\naxes_limits = [];\r\nfill_option = <span class=\"string\">'off'<\/span>;\r\nfill_transparency = 0.2;\r\ncolors = [0, 0.4470, 0.7410;<span class=\"keyword\">...<\/span>\r\n    0.8500, 0.3250, 0.0980;<span class=\"keyword\">...<\/span>\r\n    0.9290, 0.6940, 0.1250;<span class=\"keyword\">...<\/span>\r\n    0.4940, 0.1840, 0.5560;<span class=\"keyword\">...<\/span>\r\n    0.4660, 0.6740, 0.1880;<span class=\"keyword\">...<\/span>\r\n    0.3010, 0.7450, 0.9330;<span class=\"keyword\">...<\/span>\r\n    0.6350, 0.0780, 0.1840];\r\nline_style = <span class=\"string\">'-'<\/span>;\r\nline_width = 2;\r\nmarker_type = <span class=\"string\">'o'<\/span>;\r\nmarker_size = 8;\r\nfont_size = 10;\r\n\r\n<span class=\"comment\">% Check if optional arguments were specified<\/span>\r\n<span class=\"keyword\">if<\/span> numvarargs &gt; 1\r\n    <span class=\"comment\">% Initialze name-value arguments<\/span>\r\n    name_arguments = varargin(1:2:end);\r\n    value_arguments = varargin(2:2:end);\r\n    <span class=\"comment\">% Iterate through name-value arguments<\/span>\r\n    <span class=\"keyword\">for<\/span> ii = 1:length(name_arguments)\r\n        <span class=\"comment\">% Set value arguments depending on name<\/span>\r\n        <span class=\"keyword\">switch<\/span> lower(name_arguments{ii})\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'axeslabels'<\/span>\r\n                axes_labels = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'axesinterval'<\/span>\r\n                axes_interval = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'axesprecision'<\/span>\r\n                axes_precision = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'axeslimits'<\/span>\r\n                axes_limits = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'filloption'<\/span>\r\n                fill_option = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'filltransparency'<\/span>\r\n                fill_transparency = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'color'<\/span>\r\n                colors = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'linestyle'<\/span>\r\n                line_style = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'linewidth'<\/span>\r\n                line_width = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'marker'<\/span>\r\n                marker_type = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'markersize'<\/span>\r\n                marker_size = value_arguments{ii};\r\n            <span class=\"keyword\">case<\/span> <span class=\"string\">'fontsize'<\/span>\r\n                font_size = value_arguments{ii};\r\n            <span class=\"keyword\">otherwise<\/span>\r\n                error(<span class=\"string\">'Error: Please enter in a valid name-value pair.'<\/span>);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">%%% Error Check %%%<\/span>\r\n<span class=\"comment\">% Check if axes labels is a cell<\/span>\r\n<span class=\"keyword\">if<\/span> iscell(axes_labels)\r\n    <span class=\"comment\">% Check if the axes labels are the same number as the number of points<\/span>\r\n    <span class=\"keyword\">if<\/span> length(axes_labels) ~= num_data_points\r\n        error(<span class=\"string\">'Error: Please make sure the number of labels is the same as the number of points.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">else<\/span>\r\n    <span class=\"comment\">% Check if valid string entry<\/span>\r\n    <span class=\"keyword\">if<\/span> ~strcmp(axes_labels, <span class=\"string\">'none'<\/span>)\r\n        error(<span class=\"string\">'Error: Please enter in valid labels or \"none\" to remove labels.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Check if axes limits is not empty<\/span>\r\n<span class=\"keyword\">if<\/span> ~isempty(axes_limits)\r\n    <span class=\"comment\">% Check if the axes limits same length as the number of points<\/span>\r\n    <span class=\"keyword\">if<\/span> size(axes_limits, 1) ~= 2 || size(axes_limits, 2) ~= num_data_points\r\n        error(<span class=\"string\">'Error: Please make sure the min and max axes limits match the number of data points.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Check if axes precision is string<\/span>\r\n<span class=\"keyword\">if<\/span> ~ischar(axes_precision)\r\n    <span class=\"comment\">% Check if axes properties are an integer<\/span>\r\n    <span class=\"keyword\">if<\/span> floor(axes_interval) ~= axes_interval || floor(axes_precision) ~= axes_precision\r\n        error(<span class=\"string\">'Error: Please enter in an integer for the axes properties.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"comment\">% Check if axes properties are positive<\/span>\r\n    <span class=\"keyword\">if<\/span> axes_interval &lt; 1 || axes_precision &lt; 1\r\n        error(<span class=\"string\">'Error: Please enter value greater than one for the axes properties.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">else<\/span>\r\n    <span class=\"comment\">% Check if axes precision is valid string entry<\/span>\r\n    <span class=\"keyword\">if<\/span> ~strcmp(axes_precision, <span class=\"string\">'none'<\/span>)\r\n        error(<span class=\"string\">'Error: Invalid axes precision entry. Please enter in \"none\" to remove axes text.'<\/span>);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Check if not a valid fill option arguement<\/span>\r\n<span class=\"keyword\">if<\/span> ~ismember(fill_option, {<span class=\"string\">'off'<\/span>, <span class=\"string\">'on'<\/span>})\r\n    error(<span class=\"string\">'Error: Please enter either \"off\" or \"on\" for fill option.'<\/span>);\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Check if fill transparency is valid<\/span>\r\n<span class=\"keyword\">if<\/span> fill_transparency &lt; 0 || fill_transparency &gt; 1\r\n    error(<span class=\"string\">'Error: Please enter a transparency value between [0, 1].'<\/span>);\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">% Check if font size is greater than zero<\/span>\r\n<span class=\"keyword\">if<\/span> font_size &lt;= 0\r\n    error(<span class=\"string\">'Error: Please enter a font size greater than zero.'<\/span>);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p>This can be converted into an <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/arguments.html\">arguments<\/a> block.<\/p><p>\r\n<pre class=\"language-matlab\"><span style=\"color: #0000FF\">arguments<\/span>\r\n    P <span style=\"color: #A45F47\">(:,:) double<\/span>\r\n    options.AxesLabels <span style=\"color: #A45F47\">{validateAxesLabels(options.AxesLabels,P)}<\/span> = cellstr(<span class=\"string\">\"Label \"<\/span> + (1:size(P,2)))\r\n    options.AxesInterval <span style=\"color: #A45F47\">(1,1) double {mustBeInteger}<\/span> = 3\r\n    options.AxesPrecision <span style=\"color: #A45F47\">{validateAxesPrecision(options.AxesPrecision)}<\/span> = 1\r\n    options.AxesLimits <span style=\"color: #A45F47\">double {validateAxesLimits(options.AxesLimits,P)}<\/span> = []\r\n    options.FillOption <span style=\"color: #A45F47\">char {mustBeMember(options.FillOption,{'off','on'})}<\/span> = <span class=\"string\">'off'<\/span>\r\n    options.FillTransparency <span style=\"color: #A45F47\">(1,1) double {mustBeGreaterThanOrEqual(options.FillTransparency,0),mustBeLessThanOrEqual(options.FillTransparency,1)}<\/span> = 0.1\r\n    options.Color <span style=\"color: #A45F47\">(:,3) double {mustBeGreaterThanOrEqual(options.Color,0),mustBeLessThanOrEqual(options.Color,1)}<\/span> = get(groot,<span class=\"string\">'defaultAxesColorOrder'<\/span>)\r\n    options.LineStyle <span style=\"color: #A45F47\">char {mustBeMember(options.LineStyle,{'-','--',':','-.','none'})}<\/span> = <span class=\"string\">'-'<\/span>\r\n    options.LineWidth <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 2\r\n    options.Marker <span style=\"color: #A45F47\">char {mustBeMember(options.Marker,{'+','o','*','.','x','square','s','diamond','d','v','^','>','<','pentagram','p','hexagram','h','none'})}<\/span> = <span class=\"string\">'o'<\/span>\r\n    options.MarkerSize <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 8\r\n    options.FontSize <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 10\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre>\r\n<\/p><p>I also created custom validation functions for few of the arguments.<\/p><pre class=\"language-matlab\"><span class=\"keyword\">function<\/span> validateAxesPrecision(x)\r\n<span class=\"keyword\">if<\/span> isnumeric(x)\r\n    validateattributes(x,{<span class=\"string\">'double'<\/span>},{<span class=\"string\">'scalar'<\/span>,<span class=\"string\">'integer'<\/span>},mfilename,<span class=\"string\">'AxesPrecision'<\/span>)\r\n<span class=\"keyword\">else<\/span>\r\n    <span class=\"keyword\">if<\/span> ~isequal(x,<span class=\"string\">'none'<\/span>)\r\n        error(<span class=\"string\">'AxesPrecision must be a scalar integer or ''none'''<\/span>)\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"keyword\">function<\/span> validateAxesLimits(axLim,P)\r\n<span class=\"keyword\">if<\/span> ~isempty(axLim)\r\n    validateattributes(axLim,{<span class=\"string\">'double'<\/span>},{<span class=\"string\">'size'<\/span>,[2 size(P,2)]},mfilename,<span class=\"string\">'AxesLimits'<\/span>)\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"keyword\">function<\/span> validateAxesLabels(axLabels,P)\r\n<span class=\"keyword\">if<\/span> ~isequal(axLabels,<span class=\"string\">'none'<\/span>)\r\n    validateattributes(axLabels,{<span class=\"string\">'cell'<\/span>},{<span class=\"string\">'size'<\/span>,[1 size(P,2)]},mfilename,<span class=\"string\">'AxesLabels'<\/span>)\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p>These changes reduced the number of lines in the code from 500 to 400. Pretty neat!<\/p><p><b>Comments<\/b><\/p><p>Give it a try and let us know what you think <a href=\"http:\/\/blogs.mathworks.com\/pick\/?p=11088#respond\">here<\/a> or leave a <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comment\">comment<\/a> for Moses.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_9039e10d704146d2a1a695b0e353754d() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='9039e10d704146d2a1a695b0e353754d ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 9039e10d704146d2a1a695b0e353754d';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2019 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_9039e10d704146d2a1a695b0e353754d()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2019b<br><\/p><p class=\"footer\"><br>\r\n      Published with MATLAB&reg; R2019b<br><\/p><\/div><!--\r\n9039e10d704146d2a1a695b0e353754d ##### SOURCE BEGIN #####\r\n%%\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/869871 Jiro>'s\r\n% Pick this week is\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561\r\n% |spider_plot|> by\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3279387 Moses>.\r\n%\r\n% There are quite a few\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange?sort=date_desc_updated&q=spider+plot\r\n% \"spider plots\"> on the File Exchange, but this one by Moses caught my\r\n% attention for a few reasons.\r\n%\r\n% * Moses includes a detailed help inside the function.\r\n\r\nhelp spider_plot\r\n\r\n%%\r\n% * He includes a Live Script example that showcases various use cases\r\n%\r\n% <<spider_plot_livescript.png>>\r\n%\r\n% * He is very active in his communications with his users in the\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comment\r\n% comments> section and is also very diligent about updating the entry.\r\n% \r\n% * And finally, his function is another example where the new\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/function-argument-validation-1.html\r\n% Function Argument Validation> feature would be handy.\r\n%\r\n% I'm thrilled to see a nice piece of code with robust error-checking. He\r\n% has roughly 100 lines of code just for error checking the inputs to his\r\n% function. He also sets default values for the optional arguments.\r\n%\r\n% Here is the input argument processing\/error checking piece of the code.\r\n%\r\n%   %%% Data Properties %%%\r\n%   % Point properties\r\n%   [num_data_groups, num_data_points] = size(P);\r\n% \r\n%   % Number of optional arguments\r\n%   numvarargs = length(varargin);\r\n% \r\n%   % Check for even number of name-value pair argments\r\n%   if mod(numvarargs, 2) == 1\r\n%       error('Error: Please check name-value pair arguments');\r\n%   end\r\n% \r\n%   % Create default labels\r\n%   axes_labels = cell(1, num_data_points);\r\n% \r\n%   % Iterate through number of data points\r\n%   for ii = 1:num_data_points\r\n%       % Default axes labels\r\n%       axes_labels{ii} = sprintf('Label %i', ii);\r\n%   end\r\n% \r\n%   % Default arguments\r\n%   axes_interval = 3;\r\n%   axes_precision = 1;\r\n%   axes_limits = [];\r\n%   fill_option = 'off';\r\n%   fill_transparency = 0.2;\r\n%   colors = [0, 0.4470, 0.7410;...\r\n%       0.8500, 0.3250, 0.0980;...\r\n%       0.9290, 0.6940, 0.1250;...\r\n%       0.4940, 0.1840, 0.5560;...\r\n%       0.4660, 0.6740, 0.1880;...\r\n%       0.3010, 0.7450, 0.9330;...\r\n%       0.6350, 0.0780, 0.1840];\r\n%   line_style = '-';\r\n%   line_width = 2;\r\n%   marker_type = 'o';\r\n%   marker_size = 8;\r\n%   font_size = 10;\r\n% \r\n%   % Check if optional arguments were specified\r\n%   if numvarargs > 1\r\n%       % Initialze name-value arguments\r\n%       name_arguments = varargin(1:2:end);\r\n%       value_arguments = varargin(2:2:end);\r\n%       % Iterate through name-value arguments\r\n%       for ii = 1:length(name_arguments)\r\n%           % Set value arguments depending on name\r\n%           switch lower(name_arguments{ii})\r\n%               case 'axeslabels'\r\n%                   axes_labels = value_arguments{ii};\r\n%               case 'axesinterval'\r\n%                   axes_interval = value_arguments{ii};\r\n%               case 'axesprecision'\r\n%                   axes_precision = value_arguments{ii};\r\n%               case 'axeslimits'\r\n%                   axes_limits = value_arguments{ii};\r\n%               case 'filloption'\r\n%                   fill_option = value_arguments{ii};\r\n%               case 'filltransparency'\r\n%                   fill_transparency = value_arguments{ii};\r\n%               case 'color'\r\n%                   colors = value_arguments{ii};\r\n%               case 'linestyle'\r\n%                   line_style = value_arguments{ii};\r\n%               case 'linewidth'\r\n%                   line_width = value_arguments{ii};\r\n%               case 'marker'\r\n%                   marker_type = value_arguments{ii};\r\n%               case 'markersize'\r\n%                   marker_size = value_arguments{ii};\r\n%               case 'fontsize'\r\n%                   font_size = value_arguments{ii};\r\n%               otherwise\r\n%                   error('Error: Please enter in a valid name-value pair.');\r\n%           end\r\n%       end\r\n%   end\r\n%   \r\n%   %%% Error Check %%%\r\n%   % Check if axes labels is a cell\r\n%   if iscell(axes_labels)\r\n%       % Check if the axes labels are the same number as the number of points\r\n%       if length(axes_labels) ~= num_data_points\r\n%           error('Error: Please make sure the number of labels is the same as the number of points.');\r\n%       end\r\n%   else\r\n%       % Check if valid string entry\r\n%       if ~strcmp(axes_labels, 'none')\r\n%           error('Error: Please enter in valid labels or \"none\" to remove labels.');\r\n%       end\r\n%   end\r\n%   \r\n%   % Check if axes limits is not empty\r\n%   if ~isempty(axes_limits)\r\n%       % Check if the axes limits same length as the number of points\r\n%       if size(axes_limits, 1) ~= 2 || size(axes_limits, 2) ~= num_data_points\r\n%           error('Error: Please make sure the min and max axes limits match the number of data points.');\r\n%       end\r\n%   end\r\n%   \r\n%   % Check if axes precision is string\r\n%   if ~ischar(axes_precision)\r\n%       % Check if axes properties are an integer\r\n%       if floor(axes_interval) ~= axes_interval || floor(axes_precision) ~= axes_precision\r\n%           error('Error: Please enter in an integer for the axes properties.');\r\n%       end\r\n%       % Check if axes properties are positive\r\n%       if axes_interval < 1 || axes_precision < 1\r\n%           error('Error: Please enter value greater than one for the axes properties.');\r\n%       end\r\n%   else\r\n%       % Check if axes precision is valid string entry\r\n%       if ~strcmp(axes_precision, 'none')\r\n%           error('Error: Invalid axes precision entry. Please enter in \"none\" to remove axes text.');\r\n%       end\r\n%   end\r\n%   \r\n%   % Check if not a valid fill option arguement\r\n%   if ~ismember(fill_option, {'off', 'on'})\r\n%       error('Error: Please enter either \"off\" or \"on\" for fill option.');\r\n%   end\r\n%   \r\n%   % Check if fill transparency is valid\r\n%   if fill_transparency < 0 || fill_transparency > 1\r\n%       error('Error: Please enter a transparency value between [0, 1].');\r\n%   end\r\n%   \r\n%   % Check if font size is greater than zero\r\n%   if font_size <= 0\r\n%       error('Error: Please enter a font size greater than zero.');\r\n%   end\r\n%\r\n% This can be converted into an\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/arguments.html arguments>\r\n% block.\r\n%\r\n% <html>\r\n% <pre class=\"language-matlab\"><span style=\"color: #0000FF\">arguments<\/span>\r\n%     P <span style=\"color: #A45F47\">(:,:) double<\/span>\r\n%     options.AxesLabels <span style=\"color: #A45F47\">{validateAxesLabels(options.AxesLabels,P)}<\/span> = cellstr(<span class=\"string\">\"Label \"<\/span> + (1:size(P,2)))\r\n%     options.AxesInterval <span style=\"color: #A45F47\">(1,1) double {mustBeInteger}<\/span> = 3\r\n%     options.AxesPrecision <span style=\"color: #A45F47\">{validateAxesPrecision(options.AxesPrecision)}<\/span> = 1\r\n%     options.AxesLimits <span style=\"color: #A45F47\">double {validateAxesLimits(options.AxesLimits,P)}<\/span> = []\r\n%     options.FillOption <span style=\"color: #A45F47\">char {mustBeMember(options.FillOption,{'off','on'})}<\/span> = <span class=\"string\">'off'<\/span>\r\n%     options.FillTransparency <span style=\"color: #A45F47\">(1,1) double {mustBeGreaterThanOrEqual(options.FillTransparency,0),mustBeLessThanOrEqual(options.FillTransparency,1)}<\/span> = 0.1\r\n%     options.Color <span style=\"color: #A45F47\">(:,3) double {mustBeGreaterThanOrEqual(options.Color,0),mustBeLessThanOrEqual(options.Color,1)}<\/span> = get(groot,<span class=\"string\">'defaultAxesColorOrder'<\/span>)\r\n%     options.LineStyle <span style=\"color: #A45F47\">char {mustBeMember(options.LineStyle,{'-','REPLACE_WITH_DASH_DASH',':','-.','none'})}<\/span> = <span class=\"string\">'-'<\/span>\r\n%     options.LineWidth <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 2\r\n%     options.Marker <span style=\"color: #A45F47\">char {mustBeMember(options.Marker,{'+','o','*','.','x','square','s','diamond','d','v','^','>','<','pentagram','p','hexagram','h','none'})}<\/span> = <span class=\"string\">'o'<\/span>\r\n%     options.MarkerSize <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 8\r\n%     options.FontSize <span style=\"color: #A45F47\">(1,1) double {mustBePositive}<\/span> = 10\r\n% <span class=\"keyword\">end<\/span>\r\n% <\/pre>\r\n% <\/html>\r\n%\r\n% I also created custom validation functions for few of the arguments.\r\n%\r\n%   function validateAxesPrecision(x)\r\n%   if isnumeric(x)\r\n%       validateattributes(x,{'double'},{'scalar','integer'},mfilename,'AxesPrecision')\r\n%   else\r\n%       if ~isequal(x,'none')\r\n%           error('AxesPrecision must be a scalar integer or ''none''')\r\n%       end\r\n%   end\r\n%   end\r\n% \r\n%   function validateAxesLimits(axLim,P)\r\n%   if ~isempty(axLim)\r\n%       validateattributes(axLim,{'double'},{'size',[2 size(P,2)]},mfilename,'AxesLimits')\r\n%   end\r\n%   end\r\n% \r\n%   function validateAxesLabels(axLabels,P)\r\n%   if ~isequal(axLabels,'none')\r\n%       validateattributes(axLabels,{'cell'},{'size',[1 size(P,2)]},mfilename,'AxesLabels')\r\n%   end\r\n%   end\r\n%\r\n% These changes reduced the number of lines in the code from 500 to 400.\r\n% Pretty neat!\r\n%\r\n% *Comments*\r\n%\r\n% Give it a try and let us know what you think\r\n% <http:\/\/blogs.mathworks.com\/pick\/?p=11088#respond here> or leave a\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comment\r\n% comment> for Moses.\r\n\r\n##### SOURCE END ##### 9039e10d704146d2a1a695b0e353754d\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/pick\/jiro\/potw_spider_plot\/spider_plot_livescript.png\" onError=\"this.style.display ='none';\" \/><\/div><p>\r\n\r\nJiro&#8216;s Pick this week is spider_plot by Moses.There are quite a few &#8220;spider plots&#8221; on the File Exchange, but this one by Moses caught my attention for a few reasons.Moses&#8230; <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2019\/10\/18\/spider-plots-and-more-argument-validation\/\">read more >><\/a><\/p>","protected":false},"author":35,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11088"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=11088"}],"version-history":[{"count":12,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11088\/revisions"}],"predecessor-version":[{"id":11114,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11088\/revisions\/11114"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=11088"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=11088"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=11088"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}