{"id":11124,"date":"2020-02-07T09:00:17","date_gmt":"2020-02-07T14:00:17","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/?p=11124"},"modified":"2020-02-24T15:31:46","modified_gmt":"2020-02-24T20:31:46","slug":"spider-plot-ii-custom-charts-intro","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2020\/02\/07\/spider-plot-ii-custom-charts-intro\/","title":{"rendered":"Spider Plot II &#8211; Custom Charts (Intro)"},"content":{"rendered":"<div class=\"content\">\n<p><a href=\"http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495\">Sean<\/a>&#8216;s pick this week is <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561\"><tt>spider_plot<\/tt><\/a> by <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3279387\">Moses<\/a>.<\/p>\n<h3>Contents<\/h3>\n<div>\n<ul>\n<li><a href=\"#1\">Custom Charts<\/a><\/li>\n<li><a href=\"#2\">Using the Custom Chart<\/a><\/li>\n<li><a href=\"#9\">Comments<\/a><\/li>\n<\/ul>\n<\/div>\n<h3>Custom Charts<a name=\"1\"><\/a><\/h3>\n<p>My pick this week is also <tt>spider_plot<\/tt> which Jiro <a href=\"https:\/\/blogs.mathworks.com\/pick\/2019\/10\/18\/spider-plots-and-more-argument-validation\/\">picked a few months ago<\/a>. Jiro added argument validation, of which we&#8217;re obviously big fans(!), to it. Here, I&#8217;m going to take it a step further and create a <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2019b\/matlab\/developing-chart-classes.html\">custom chart<\/a> for it; this is also a new R2019b feature.<\/p>\n<p>If you look at the signature for <tt>spider_plot<\/tt> now, it does not return an output argument. If you want to change it after it&#8217;s created, you either need to find the underlying graphics objects using <tt>findobj<\/tt> and adjust them, or delete and recreate the chart, probably by clearing the axes with <tt>cla<\/tt>. The pieces of the spider_plot may show up in the graphics hierarchy, but the spider_plot itself will not. Because they&#8217;re not encapsulated, a user could corrupt them accidentally or struggle to make a change that looks like what they want.<\/p>\n<p>By creating a custom chart we get the benefits of encapsulation, our object appearing in the graphics hierarchy, automatic input handling, and give a chart user the same experience they would have with a MathWorks authored chart (e.g. <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2019b\/stats\/confusionchart.html\"><tt>confusionchart<\/tt><\/a>, <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2019b\/matlab\/ref\/heatmap.html\"><tt>heatmap<\/tt><\/a>). Additionally, and possibly most importantly, by creating a custom chart, we can tie into the automatic updates in the graphics system hierarchy caused by <tt>drawnow<\/tt> in order to be efficient about updates.<\/p>\n<h3>Using the Custom Chart<a name=\"2\"><\/a><\/h3>\n<p>Over the holiday downtime, I converted Moses&#8217; <tt>spider_plot<\/tt> to a custom chart, I&#8217;ve creatively named <tt>SpiderChart<\/tt>. Today, let&#8217;s just play with the finished chart.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s = SpiderChart(rand(3,5))<\/pre>\n<pre style=\"font-style: oblique;\">s = \r\n\r\n  SpiderChart with properties:\r\n\r\n                   P: [3\u00d75 double]\r\n        AxesInterval: 3\r\n       AxesPrecision: 1\r\n          AxesLimits: []\r\n          FillOption: off\r\n    FillTransparency: 0\r\n               Color: [7\u00d73 double]\r\n           LineStyle: '-'\r\n           LineWidth: 2\r\n              Marker: 'o'\r\n          MarkerSize: 8\r\n       LabelFontSize: 10\r\n        TickFontSize: 10\r\n          AxesLabels: [1\u00d7100 string]\r\n          DataLabels: [1\u00d7100 string]\r\n            Position: [0.1300 0.1100 0.7750 0.8150]\r\n               Units: 'normalized'\r\n\r\n  Use GET to show all properties\r\n\r\n<\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_01.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>You can see that the returned object is a <tt>SpiderChart<\/tt>. Now, let&#8217;s adjust the filling:<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.FillOption = <span style=\"color: #a020f0;\">'on'<\/span>;\r\ns.FillTransparency = 0.5;<\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_02.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>And adjust the label of the third axis.<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.AxesLabels(3) = <span style=\"color: #a020f0;\">\"I'm three!\"<\/span>;<\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_03.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>What about if the data change?<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.P = randn(2,6);<\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_04.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p>See how everything updated for this?<\/p>\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">s.DataLabels = [<span style=\"color: #a020f0;\">\"MATLAB\"<\/span> <span style=\"color: #a020f0;\">\"Simulink\"<\/span>];\r\nlegend <span style=\"color: #a020f0;\">show<\/span><\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_05.png\" hspace=\"5\" vspace=\"5\" \/><\/p>\n<p><a href=\"https:\/\/blogs.mathworks.com\/pick\/?p=11287\">Next week<\/a>, we&#8217;ll look at authoring the custom chart!<\/p>\n<h3>Comments<a name=\"9\"><\/a><\/h3>\n<p>Do you have a use for custom charts or a chart you would like MathWorks to make?<\/p>\n<p>Give it a try and let us know what you think <a href=\"http:\/\/blogs.mathworks.com\/pick\/?p=11124#respond\">here<\/a> or leave a <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comments\">comment<\/a> for Moses.<\/p>\n<p><script language=\"JavaScript\">\n<!--\n\n    function grabCode_9348b4f6211b4b9180456d43d71b4093() {\n        \/\/ Remember the title so we can use it in the new page\n        title = document.title;\n\n        \/\/ Break up these strings so that their presence\n        \/\/ in the Javascript doesn't mess up the search for\n        \/\/ the MATLAB code.\n        t1='9348b4f6211b4b9180456d43d71b4093 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 9348b4f6211b4b9180456d43d71b4093';\n    \n        b=document.getElementsByTagName('body')[0];\n        i1=b.innerHTML.indexOf(t1)+t1.length;\n        i2=b.innerHTML.indexOf(t2);\n \n        code_string = b.innerHTML.substring(i1, i2);\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\n\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \n        \/\/ in the XML parser.\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\n        \/\/ doesn't go ahead and substitute the less-than character. \n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\n\n        author = 'Sean de Wolski';\n        copyright = 'Copyright 2020 The MathWorks, Inc.';\n\n        w = window.open();\n        d = w.document;\n        d.write('<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\n<\/p>\n\n\n\n\n<p>\\n');\n      \n      d.title = title + ' (MATLAB code)';\n      d.close();\n      }   \n      \n-->\n<\/script><br \/>\nPublished with MATLAB\u00ae R2020a<\/p>\n<\/div>\n<p><!--\n9348b4f6211b4b9180456d43d71b4093 ##### SOURCE BEGIN #####\n%% Spider Plot II\n%\n% <http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495 Sean>'s pick this week is\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561 |spider_plot|> by\n% <http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3279387 Moses>.\n%\n\n%% Custom Charts\n%\n% My pick this week is also |spider_plot| which Jiro\n% <https:\/\/blogs.mathworks.com\/pick\/2019\/10\/18\/spider-plots-and-more-argument-validation\/ % picked a few months ago>. Jiro added argument validation, of which we're\n% obviously big fans(!), to it.  Here, I'm going to take it a step further\n% and create a\n% <https:\/\/www.mathworks.com\/help\/releases\/R2019b\/matlab\/developing-chart-classes.html % custom chart> for it; this is also a new R2019b feature.\n%\n% If you look at the signature for |spider_plot| now, it does not return an\n% output argument.  If you want to change it after it's created, you either\n% need to find the underlying graphics objects using |findobj| and adjust\n% them, or delete and recreate the chart, probably by clearing the axes\n% with |cla|.  The pieces of the spider_plot may show up in the graphics\n% hierarchy, but the spider_plot itself will not.  Because they're not\n% encapsulated, a user could corrupt them accidentally or struggle to make\n% a change that looks like what they want.\n%\n% By creating a custom chart we get the benefits of encapsulation, our\n% object appearing in the graphics hierarchy, automatic input handling, and\n% give a chart user the same experience they would have with a MathWorks\n% authored chart (e.g.\n% <https:\/\/www.mathworks.com\/help\/releases\/R2019b\/stats\/confusionchart.html % |confusionchart|>,\n% <https:\/\/www.mathworks.com\/help\/releases\/R2019b\/matlab\/ref\/heatmap.html % |heatmap|>).  Additionally, and possibly most importantly, by creating a\n% custom chart, we can tie into the automatic updates in the graphics\n% system hierarchy caused by |drawnow| in order to be efficient about\n% updates.\n%\n%% Using the Custom Chart\n%\n% Over the holiday downtime, I converted Moses' |spider_plot| to a custom\n% chart, I've creatively named |SpiderChart|.  First let's just play with\n% the finished chart.\n\ns = SpiderChart(rand(3,5))\n\n%%\n% You can see that the returned object is a |SpiderChart|.  Now, let's\n% adjust the filling:\n\ns.FillOption = 'on';\ns.FillTransparency = 0.5;\n\n%%\n% And adjust the label of the third axis.\ns.AxesLabels(3) = \"I'm three!\";\n\n%%\n% What about if the data change?\ns.P = randn(2,6);\n\n%%\n% See how everything updated for this?\ns.DataLabels = [\"MATLAB\" \"Simulink\"];\nlegend show\n\n%% Authoring the Custom Chart\n%\n% Now let's look at the steps to author this chart.\n%\n% First we need a class that inherits from\n% |matlab.graphics.chartcontainer.ChartContainer|.\n%\n%   classdef SpiderChart < matlab.graphics.chartcontainer.ChartContainer & ... % matlab.graphics.chartcontainer.mixin.Legend % % It needs a public property for everything we want our end users to be % able to set or get. You'll notice defaults and validation are done on % the property level. % % classdef XX % properties (SetObservable) % P {mustBeNumeric} % AxesInterval(1,1) double {mustBeInteger} = 3 % Number of axes grid lines % AxesPrecision = 1 % Tick precision % AxesLimits = [] % Axes limits % FillOption matlab.lang.OnOffSwitchState = 'off' % Whether to shade data % FillTransparency(1,1) double {mustBeGreaterThanOrEqual(FillTransparency,0),mustBeLessThanOrEqual(FillTransparency,1)} % Shading alpha % Color(:,3) double {mustBeGreaterThanOrEqual(Color,0),mustBeLessThanOrEqual(Color,1)} = get(groot,'defaultAxesColorOrder') % Color order % LineStyle {mustBeMember(LineStyle,{'-','REPLACE_WITH_DASH_DASH',':','-.','none'})} = '-' % Data line style % LineWidth(1,1) double {mustBePositive} = 2 % Data line width % Marker {mustBeMember(Marker,{'+','o','*','.','x','square','s','diamond','d','v','^','>','<','pentagram','p','hexagram','h','none'})} = 'o' % Data marker\n%      MarkerSize(1,1) double {mustBePositive} = 8 % Data marker size\n%      LabelFontSize(1,1) double {mustBePositive} = 10 % Label font size\n%      TickFontSize(1,1) double {mustBePositive} = 10 % Tick font size\n%      AxesLabels = \"Label \" + (1:100); % Axes labels\n%      DataLabels = \"Data \" + (1:100); % Data labels\n%   end\n%   end\n%\n% We also need properties for the underlying graphics object that our\n% chart will create, adjust, or destroy as necessary.  These can't be saved\n% or replicated so they'll be _Transient_ and _NonCopyable_.\n%\n%   classdef XX\n%   properties (Access = private, Transient, NonCopyable)\n%       ThetaAxesLines = gobjects(0)\n%       RhoAxesLines = gobjects(0)\n%       DataLines = gobjects(0)\n%       LabelObjects = gobjects(0)\n%       FillPatches = gobjects(0)\n%       AxesTextLabels = gobjects(0)\n%       AxesTickLabels = gobjects(0)\n%       DoWholeUpdate = true\n%       AxesValues\n%   end\n%   end\n%\n% Then we need a constructor.  I want my class to have both normal syntaxes\n% for a chart, i.e.:\n%\n%   SpiderChart(data)\n%   SpiderChart(data, 'Name', value, ...)\n%   SpiderChart(parent, ____)\n%\n% so I'll handle this in the constructor.\n%\n%   % Constructor\n%   function obj = SpiderChart(parentOrP, varargin)\n%       narginchk(1, inf);\n%       if isa(parentOrP, 'matlab.graphics.Graphics')\n%       % SpiderPlot(parent, P, 'name', value)\n%          in = [{parentOrP, 'P'}, varargin];\n%       else\n%          % SpiderPlot(P, 'name', value)\n%          in = [{'P', parentOrP} varargin];\n%       end\n%       % Construct\n%       obj@matlab.graphics.chartcontainer.ChartContainer(in{:});\n%   end\n%\n% With a custom chart, we need to have a |setup| and |update| method.\n% The setup runs once when the chart is constructed and update any time a\n% property is changed and a |drawnow| called.\n%\n% There are two properties (_P_, _AxesInterval_) that when changed could\n% require adjusting the total number of graphics objects needed (i.e. could\n% require creating or deleting objects in an update).  Because of this, the\n% only thing I'll do in |setup| is set the axes properties.  The update\n% will deal with graphics object creation.\n%\n%\n%   function setup(obj)\n%   % Configure axes\n%   ax = getAxes(obj);\n%   hold(ax, 'on')\n%   axis(ax, 'square')\n%   axis(ax, 'off')\n%   end\n%\n% The decision of whether to destroy and recreate objects is based on a\n% _DoWholeUpdate_ property that is adjusted in the setters for the\n% aforementioned properties.  It also defaults to true so on first run,\n% everything is created.\n%\n%   %Update implementation\n%   function update(obj)\n%       if obj.DoWholeUpdate\n%           % Only reset and reinitialize if P or AxesInterval changed\n%           resetStoredGraphicsObjects(obj);\n%           initializeEverything(obj)\n%           obj.DoWholeUpdate = false;\n%       end\n%       adjustAppearances(obj);\n%   end\n%\n% These are the setters that toggle updating everything.\n%\n%   function set.P(obj, val)\n%       obj.P = val;\n%       obj.DoWholeUpdate = true;\n%   end\n%\n%   function set.AxesInterval(obj, val)\n%       obj.AxesInterval = val;\n%       obj.DoWholeUpdate = true;\n%   end\n%\n% From the |update| method, you can see there are three main algorithmic\n% parts: |resetStoredGraphicsObjects|, |initializeEverything|, and\n% |adjustAppearances|.\n%\n% The reset step deletes old graphics objects and reinitializes the\n% properties to empty graphics placeholders.\n%\n%   function resetStoredGraphicsObjects(obj)\n%   % Delete old objects\n%   delete(obj.ThetaAxesLines)\n%   delete(obj.RhoAxesLines)\n%   delete(obj.DataLines)\n%   delete(obj.LabelObjects)\n%   delete(obj.FillPatches)\n%   delete(obj.AxesTextLabels)\n%   delete(obj.AxesTickLabels)\n%\n%   % Preallocate new ones as empties\n%   obj.ThetaAxesLines = gobjects(0);\n%   obj.RhoAxesLines = gobjects(0);\n%   obj.DataLines = gobjects(0);\n%   obj.LabelObjects = gobjects(0);\n%   obj.FillPatches = gobjects(0);\n%   obj.AxesTextLabels = gobjects(0);\n%   obj.AxesTickLabels = gobjects(0);\n%   obj.AxesValues = [];\n%   end\n%\n% Next, we initialize new objects where the number of objects is based on\n% the size of _P_ and the _AxesInterval_.  All of them are initialized\n% invisible with no data associated to them.  This is the biggest change I\n% had to make from the original code - I.e. rather than creating objects\n% and not retaining their handles, I need to create them without setting\n% their customizable properties, store the handles, and then adjust those\n% properties later.\n%\n% <include>initevery.m<\/include>\n%\n% And then finally, adjust the appearances based on the properties.  This\n% fires any time any of the properties are changed.  It updates the\n% properties of the underlying graphics objects to implement the change.\n%\n% <include>adjustapp.m<\/include>\n%\n%\n\n%% Full Custom Chart\n%\n% Obviously, it took some effort, design, and a lot of refactoring to turn\n% this into a custom chart and there are still further improvements that\n% could be made (e.g. not updating everything, but one property at a time).\n% If you want to play with it yourself, here is the full |SpiderChart.m|\n% class definition file.  I took the liberty to make a couple enhancements\n% to Moses' original, e.g. separating label fontsize and tick fontsize and\n% making things work with string arrays.\n%\n% <include>SpiderChart.m<\/include>\n\n%% Comments\n% Do you have a use for custom charts or a chart you would like MathWorks\n% to make?\n%\n% Give it a try and let us know what you think\n% <http:\/\/blogs.mathworks.com\/pick\/?p=11124#respond here> or leave a\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/59561#comments % comment> for Moses.\n##### SOURCE END ##### 9348b4f6211b4b9180456d43d71b4093\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"http:\/\/blogs.mathworks.com\/images\/pick\/Sean\/mainSpiderChart\/mainSpiderChart_01.png\" onError=\"this.style.display ='none';\" \/><\/div>\n<p>\nSean&#8216;s pick this week is spider_plot by Moses.<br \/>\nContents<\/p>\n<p>Custom Charts<br \/>\nUsing the Custom Chart<br \/>\nComments<\/p>\n<p>Custom Charts<br \/>\nMy pick this week is also spider_plot which Jiro picked a few months&#8230; <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2020\/02\/07\/spider-plot-ii-custom-charts-intro\/\">read more >><\/a><\/p>\n","protected":false},"author":87,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[7,16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11124"}],"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\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=11124"}],"version-history":[{"count":14,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11124\/revisions"}],"predecessor-version":[{"id":11333,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/11124\/revisions\/11333"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=11124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=11124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=11124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}