Editor's Note:
This file was selected as MATLAB Central Pick of the Week February 7, 2020
This file was selected as MATLAB Central Pick of the Week October 18, 2019
Create a simple yet professionally looking spider or radar plot. Each axis limits can be set manually. Please refer to the documentation in the github readme page (https://github.com/NewGuy012/spider_plot) for all the plot settings that can be customized.
The three functions included have the same functionality but with 3 different implementation:
• spider_plot() is compatible with most MATLAB versions.
• spider_plot_R2019b() is compatible with R2019b and above. It uses the new argument validation feature.
• spider_plot_R2019b_class() is compatible with R2019b and above. It uses the new chart class feature.
Moses (2020). spider_plot (https://github.com/NewGuy012/spider_plot), GitHub. Retrieved .
5.3  Added feature to allow change in spider axes and legend edge colors. 

5.2  Allow logarithmic scale to be set to one or more axis. 

5.1  Allow for different marker and line styles for each line. 

5.0  Created an implementation of new chart classes introduced in R2019b. 

4.6  Fixed a few bugs and added a few more error checking. See log in documentation for details. 

4.5  Added support for tiledlayout feature introduced in R2019b. 

4.4  Added option to change axes scale to logarithmic scale.


4.3  Added feature to customize the rotational direction in which the data and labels are plotted. 

4.2  Minor revision to set starting axes as the vertical line.


4.1  Minor revision to add namevalue pairs for customizing color, marker, and line settings. 

4.0  Another major revision converting varargin arguments to namevalue pairs and adding a color fill feature 

3.3  Update plot order to correctly display the legend. 

3.2  Adjust label offset and main axes thickness. 

3.1  Changed image to include legend. 

3.0  Major revision to improve speed, clarity, and functionality. 

2.2.1  Added offset to outer web diameter. 

2.2.0.0  Updated comments. 

2.1.0.0  Modified comments to reflect changes. 

2.0.0.0  Fixed to correctly display negative numbers.


1.8.0.0  Updated example in comments. 

1.7.0.0  Fixed inconsistency in variable name, example scripts, and in plot color scheme. 

1.6.0.0  Added a separate spider plot function to display the values on each axes. 

1.5.0.0  1. Correct example in description. 

1.4.0.0  1. Add example script in description 

1.3.0.0  1. Update the function's image. 

1.2.0.0  1. Correct some spelling error in comments. :) 

1.1.0.0  1. Added more comments to clarify what the row and column of the input data points correspond to. 
Create scripts with code, output, and formatted text in a single executable document.
Gábor Remzso (view profile)
Moses (view profile)
Hi Mohamed, thank you for the comment. I think your feedback is a good idea to incorporate as a feature. I will look to add it in the next version. Thanks.
Mohamed Abubakr (view profile)
Hi Moses
Great work
For everybody wondering how to turn off the box around the axis label, you replace line 808 with the following
Line 808: 'EdgeColor', 'none',...
Also, you can have lighter axes by modifying the following line
Line 530: grey = [0.8, 0.8, 0.8];
or even lighter
Line 530: grey = [0.9, 0.9, 0.9];
This will give you a little simpler look if that what you are looking for.
Moses (view profile)
Hi Mariusz, I just updated the spider_plot() function to allow different scales for each axes. Please refer to the updated example #6.
***This feature has not been implemented in spider_plot_R2019b() or spider_plot_R2019b_class() yet.
Thanks,
Mariusz Sepczuk (view profile)
HI,
Is it possibile to change a scale only for a one axe? For example, all axes may have a linear scale but one should have a log scale.
Alvise Miotti Bettanini (view profile)
yuqiang li (view profile)
Hi Moses
Thank you for providing this great function.
From China.
Moses (view profile)
Hi Roman, thank you for the feature suggestions! I will look to add it in the next update.
Roman (view profile)
Hi Moses
Thanks for sharing this great function.
I've changed the code in spider_plot.m to allow setting different linestyles etc. for the lines by
A) adding the following code after line 563:
%create array for line_style, line_width, marker_type, marker_size with same size as num_data_groups
line_style = cellstr(line_style); %convert to cell array
if length(line_style) ~= num_data_groups
line_style = repmat(line_style(1),1,num_data_groups);
end
marker_type = cellstr(marker_type); %convert to cell array
if length(marker_type) ~= num_data_groups
marker_type = repmat(marker_type(1),1,num_data_groups);
end
if length(line_width) ~= num_data_groups
line_width = repmat(line_width(1),1,num_data_groups);
end
if length(marker_size) ~= num_data_groups
marker_size = repmat(marker_size(1),1,num_data_groups);
end
B) Adjusting the plot command in line 574 as follows:
plot(x_circular, y_circular,...
'LineStyle', line_style{ii},...
'Marker', marker_type{ii},...
'Color', colors(ii, :),...
'LineWidth', line_width(ii),...
'MarkerSize', marker_size(ii),...
'MarkerFaceColor', colors(ii, :));
This way you can provide a cell array / array for the linestyle, linewidth, markersize, marker. If it does not match the amount of group, it will just use the first entry given in this array.
Feel free to add this to the function.
Have a good day
Best regards,
Roman
Roman (view profile)
Ichechi Weli (view profile)
Moses (view profile)
Hi Christophe, thank you for trying out the function. Yes, the spider for one num_data_group appears that way because the axis limits are automatically scaled to the min and max values of each data group. To get around this, you have to manually specify the desired axis limits such as in the example below.
======================================
P = [5 3 9 1 2];
spider_plot_R2019b(P, 'AxesLimits', [1, 1, 1, 1, 1; 10, 10, 10, 10, 10]);
======================================
Victor Ignacio (view profile)
Christophe Hurlin (view profile)
Thank you for this very useful function. However, it seems that the function spider_plot_R2019b does not produce a radar plot if we have only one num_data_group. For instance, if I launch P=[5 3 9 1 2]; spider_plot_R2019b(P), the 5 axis appear but not the radar itself. Thanks.
Moses (view profile)
Hello Zafar, thank you for the feedback. I've made the fix to allow for more than seven legends. Please download the latest code and try it again. Thanks.
Zafar Ali (view profile)
When I add more than seven legends, it gives an error. For seven and less legends, it works fine. Please help me. Thank you
Moses (view profile)
Hello Omar, I apologize for the delayed response while on break. Thank you for the feature request; I've updated the function to add support for the titledlayout feature. You can now use spider_plot_R2019b() the same way you would use the plot() function such as in the example below:
======================================
t = tiledlayout(2,2);
% Initialize data points
D1 = [5 3 9 1 2];
D2 = [5 8 7 2 9];
D3 = [8 2 1 4 6];
P = [D1; D2; D3];
% Spider plot
nexttile
spider_plot_R2019b(P);
% Spider plot
nexttile
spider_plot_R2019b(P);
% Spider plot
nexttile
spider_plot_R2019b(P);
% Spider plot
nexttile
spider_plot_R2019b(P);
t.TileSpacing = 'compact';
t.Padding = 'compact';
======================================
Omar Hadri (view profile)
Can you include tiledlayout support in future versions, I am using it like this for now
======================================
function spider_plot_R2019b(tile_loc,tile_x,tile_y, P, options)
...
arguments
tile_loc (:, :) double
tile_x (:, :) double
tile_y (:, :) double
...
end
....
%%% Figure Properties %%%
% Figure background
% fig = figure;
% fig.Color = 'white';
nexttile(tile_loc,[tile_x,tile_y]);
....
% Find object handles
text_handles = findobj(nexttile(tile_loc,[tile_x,tile_y]).Children,...
'Type', 'Text');
patch_handles = findobj(nexttile(tile_loc,[tile_x,tile_y]).Children,...
'Type', 'Patch');
isocurve_handles = findobj(nexttile(tile_loc,[tile_x,tile_y]).Children,...
'Color', grey,...
'and', 'Type', 'Line');
plot_handles = findobj(nexttile(tile_loc,[tile_x,tile_y]).Children, 'not',...
'Color', grey,...
'and', 'Type', 'Line');
....
Moses (view profile)
Hi Tobias, yes, I've updated the function to allow for logscaling on all axes. Please download the latest version and take a look at example #6.
Tobias Kern (view profile)
Hi Moses, first thanks for sharing this useful feature! I wanted to know if there is an easy option to implement a logscaling on all axes?
Moses (view profile)
Hi Alex, thank you for the useful feature suggestion! I've just updated the function to allow for clockwise plotting. Please take a look at the latest example.
Alex Grenyer (view profile)
Hi, thanks for this very useful function!
A small thing  the function appears to plot inputs anticlockwise (for P1x). Is it possible to plot them clockwise?
cui (view profile)
very nice! easy to use!
dongdong Geng (view profile)
Nice tool.
Moses (view profile)
Hi Matteo,
I updated the code to make color, marker, and line settings into namevalue pair arguments. If you'd like, please download the latest version and see the examples.
Thanks,
Moses
Matteo Bilardo (view profile)
Hi Moses, thank you for the useful function.
I just have a question: how can I change the colors of the curves? I would like to customize the color of the lines.
Thank you in advance,
Matteo
Moses (view profile)
Hi Arnold, thank you for the feature request. I've added the ability to inscribe the polygon with color now with adjustable transparency, so please take a look at the latest example with the latest version.
arnold (view profile)
Is there a way to fill the inscribed polygon with a color, ideally with some transparency?
Moses (view profile)
Hello Andres,
Thank you for pointing out the min_values(i) and the suggestion to implement a manual axes limit! I think that is a great idea to avoid changing specific lines in the code. I will be looking to update the function on the next release.
Best regards,
Moses
Andrés Garcia (view profile)
To end up, this is an error detection code in order to make sure that all data is between given ranges for every axis. It can be put almost anywhere in the spyder plot function:
% Error detection for outofrange values
for i = 1:size(P,1)
for j = 1:size(P,2)
if P(i,j) > max_values(j)  P(i,j) < min_values(j)
error("Error: The value for the attribute number " + num2str(j) + ...
" in the streaming number " + num2str(i) + ...
" is out of the given range for that attribute. Check it again");
end
end
end
Andrés Garcia (view profile)
And above all Moses, here I leave the missing piece of code allowing to choose which axes are increasing or decreasing when going radially out. But you must pass as an argument to the spyder_plot program called axesLimits, where you put the wished "furthest" value for every axis on the first row and the wished "closest" value of the origin on the second row.
First you must add this pàrt in the normalization of the data:
% Preallocation
max_values = zeros(1, numOfAttributes);
min_values = zeros(1, numOfAttributes);
axis_increment = zeros(1, numOfAttributes);
reverse = false(1,numOfAttributes);
if isempty(axesLimits)
for i = 1:numOfAttributes
[INSERT HERE THE PREVIOUS CODE, SO IT DYNAMICALLY TAKES MAX AND MIN]
end
else
% Max and min value of each attribute
max_values = max(axesLimits,[],1);
min_values = min(axesLimits,[],1);
for i = 1:numOfAttributes
range = max_values(i)  min_values(i);
axis_increment(i) = range/axes_interval;
% Normalize points to range from [0, 1]
P(:, i) = (P(:, i)min_values(i))/range;
if axesLimits(1,i) < axesLimits(2,i)
reverse(i) = true;
end
% Shift points by one axis increment. If not, the lowest point on each
% axis would be 0. Now, it will be on the first division between 0 and
% 1 and maximum on each axis on the outer perimeter of the graph.
if reverse(i) == false
P(:, i) = P(:, i) + normalized_axis_increment;
end
end
Then in the part of locating the data points on the plot:
x_points = zeros(1,numOfAttributes);
y_points = zeros(1,numOfAttributes);
% Convert polar to cartesian coordinates
for n = 1:numOfAttributes
if reverse(n) == true
[x_points(n), y_points(n)] = pol2cart(theta(n), axes_limitP(m, n));
else
[x_points(n), y_points(n)] = pol2cart(theta(n), P(m, n));
end
end
% Make points circular
x_circular = [x_points, x_points(1)];
y_circular = [y_points, y_points(1)];
And finally on the placing of the labels for each axis:
% Iterate through all the number of points  Labels
for n = 1:numOfAttributes
if reverse(n) == true
% Shifted max value
shifted_max_value = max_values(n)+axis_increment(n);
% Axis label for each row
row_axis_labels = (min_values(n):axis_increment(n):shifted_max_value)';
% Iterate through all the isocurve radius
for p = 2:length(radius)
% Display axis text for each isocurve
text(x_isocurves(p, n), y_isocurves(p, n), sprintf(sprintf('%%.%if', axes_precision),...
row_axis_labels(length(radius)p+1)),...
'Units', 'Data',...
'Color', 'k',...
'FontSize', 10,...
'HorizontalAlignment', 'center',...
'VerticalAlignment', 'middle');
end
else
% Shifted min value
shifted_min_value = min_values(n)axis_increment(n);
% Axis label for each row
row_axis_labels = (shifted_min_value:axis_increment(n):max_values(n))';
% Iterate through all the isocurve radius
for p = 2:length(radius)
% Display axis text for each isocurve
text(x_isocurves(p, n), y_isocurves(p, n), sprintf(sprintf('%%.%if', axes_precision), row_axis_labels(p)),...
'Units', 'Data',...
'Color', 'k',...
'FontSize', 10,...
'HorizontalAlignment', 'center',...
'VerticalAlignment', 'middle');
end
end
end
Hope it helps you for the next release Moses! Hope you do well
Andrés Garcia (view profile)
Careful! On the normalization command you use to transform your data values, you substract the variable min(groups) when it would be more coherent to do with min_values(i). That won't change a thing if your program is untouched but since you are advising a lot of people to change the min and max values with values of their own, it will be needed to substract the minimum you want, as you did with the command to calculate the range.
Andrés Garcia (view profile)
Henry Ip (view profile)
Allison Miller (view profile)
Moses (view profile)
Hi Elora,
No problem, yes, it is easy to set the manually set the scale of all the axes to a specific can be done by changing lines 110111 to a specific value:
% % Max and min value of each group
% max_values(ii) = max(group_points);
% min_values(ii) = min(group_points);
You can refer to Tracy's question below for reference.
To change only a specific axes, however, the quickest way might be to replace the code as such:
% Max and min value of each group
if ii == (some index number)
max_values(ii) = 9;
min_values(ii) = 0;
elseif ii == (some index number)
max_values(ii) = 400;
min_values(ii) = 0;
else
max_values(ii) = max(group_points);
min_values(ii) = min(group_points);
end
Where the "some index number" part is the column index of the array "P" that you wish to set the axes.
elora leguebe (view profile)
hello Moses,
sorry to bother you but you may know how to help me.
I used your program to make my graph that went very well and I thank you for it. However, I would have liked to change the axes and I can not do it. I would need two, one horizontal and one vertical with a scale from 0 to 9 and from 0 to 400. Would you know how make?
This is my script :
clear workspace
close all;
clearvars;
clc;
% % Point properties
num_of_points = 59;
row_of_points = 5;
% % Data
load X4.txt
P1=X4(:,1);
P2=X4(:,2);
P3=X4(:,3);
P4=X4(:,4);
P5=X4(:,5);
P6=X4(:,6);
Pbis=[P2,P3,P4,P5,P6];
P=transpose(Pbis);
% % Create generic labels
P_labels=cell(1,num_of_points);
for ii = 1:num_of_points
P_labels{ii} = sprintf('%g', P1(ii,1));
end
% % Figure properties
figure('units', 'normalized', 'outerposition', [0 0.05 1 0.95]);
%
% % Axes properties
axes_interval = 2;
axes_precision = 1;
%
% % Spider plot
spider_plot(P, P_labels, axes_interval, axes_precision, 'Marker', '+', 'LineStyle', '', 'LineWidth', 2,'MarkerSize', 5);
%
% % Title properties
%title('Radar','Fontweight', 'bold', 'FontSize', 12);
%
% % Legend properties
legend('vitesse de montée','vitesse de banderolage','étirage','préétirage','masse','Location', 'southoutside');
Moses (view profile)
Hi Yat Sheng Kong,
It seems the error is originating either the way that the ismember function is being used or the way that the parallel computing toolbox is being used. Either case, there is something strange going on since the spider plot function does not require either ismember or the parallel computing toolbox.
For the ismember function, please check the following:
https://www.mathworks.com/matlabcentral/answers/152217ismemberlegacyflagwitholdermatlab
https://stackoverflow.com/questions/20494721/matlabbuginismember
and for the IdleTimeout error, please check the following:
https://www.mathworks.com/matlabcentral/answers/179509parallelprogrammingtoolboxshuttingdown
https://www.mathworks.com/matlabcentral/answers/410692parallelpoolshutdownduringtheiteration
I would isolate the problem by trying to run the function without the dependencies on these two problems and work from there. Hope this helps!
Yat Sheng Kong (view profile)
Hi Jakob,
I run using Matlab 2018 and it gives me this error.
Error in ismember>ismemberR2012a (line 196)
lia = ismemberClassTypes(a,b);
IdleTimeout has been reached.
Parallel pool using the 'local' profile is shutting down.
Is it a computer problem?
Moses (view profile)
Hi Jakob,
What are your inputs to the functions? My initial guess is that you may need to transpose the array P. I would suggest using the example script in the description above and replacing the data with yours to see if it works.Thank you.
Jakob (view profile)
Hi Moses, thanks for sharing! I am trying to plot only one data set but keep getting this error:
Index exceeds the number of array elements (0).
Error in spider_plot (line 221)
text(x_isocurves(ii, hh), y_isocurves(ii, hh), sprintf(sprintf('%%.%if',
axes_precision), row_axis_labels(ii)),...
Error in Untitled (line 86)
spider_plot(P, P_labels, axes_interval, axes_precision);
Any advice?
Moses (view profile)
Hi Libor, I am glad you found it useful. I have noticed that other users have reported that the function sometimes takes some time to make it operational. If you have any feedback on what you did and how I can make it more compatible with various MATLAB releases, that would be much appreciated.
Regarding the legend strings, you just need to change the legend command with a cell of strings of your choice or use the P_labels variable in the sample code provided.
% Legend properties
legend(P_labels, 'Location', 'southoutside');
or
legend({'string of your choice'}, 'Location', 'southoutside');
Thank you for the suggestion. Reversing the axes orientation was something I had in mind, and may be implemented in the next version.
Libor Rufer (view profile)
Dear Moses,
Thank you for this nice and useful function!
It took me some time to make it operational, but then, I did what I was looking for!
There will be all the time some possible improvements that I managed indirectly.
For instance, I would be interested to enter strings, which will appear in the legend instead of data1, 2, ...
Could you guide me, please?
Another thing could be to decide the axes orientation, it is sometimes better to have a minimal value on the top.
I have arranged this by inputing negative values, which was sufficient for me.
Thank you again, Libor
Kurt Stewart (view profile)
Thanks for this
Chunhui Zhu (view profile)
Hi Freya, if you also need min value to be standardized, you need to change line 118 to be:
P(:, ii) = (P(:, ii)min(min(P)))/range;
(otherwise the range will be shrinking in the radar plot and lead to wrong plot result)
Moses (view profile)
Hi Freya,
Thank you for catching that typo in the description. I will correct it in the next version released.
Freya H (view profile)
Hi Moses,
sorry for that previous comment, which happened by accident & apparently I cannot delete it again.
Thank you for the great spider plot!
I just have a super small comment: P_labels in your example script is a cell of chars, not strings (as mentioned in the function description). But neither chars nor strings cause an error, so I guess it doesn't matter too much ;)
Moctar DEMBELE (view profile)
I finally used the pol2cartvect function of Gabriela and it's working. Thanks!
Moses (view profile)
Hi Daniel,
It sounds like it might be due to some function names being in conflict, causing a function to call itself recursively without intention. Please see the MATLAB Answers articles below for reference.
https://www.mathworks.com/matlabcentral/answers/218422howtogetridoftheerrormessageset0recursionlimitn
https://www.mathworks.com/matlabcentral/answers/242157errorswhenusingcloseorcloseall
In the article, the function unique.m was causing the error, but depending on your code it may be a different function name.
Daniel Ng (view profile)
Hi Moses,
I tried running the script with the function file. However, I receive and error message stating:
"Maximum recursion limit of 500 reached. Use
set(0,'RecursionLimit',N) to change the limit. Be aware that
exceeding your available stack space can crash MATLAB and/or
your computer.
Error in ismemberCismemberClassTypes"
I am not sure what is the error referring to specifically. Could you advice me? Thank you.
Daniel
henyan deng (view profile)
Moses (view profile)
Hi Tracy,
By default it uses the max and min of the data and the axes_interval input argument to determine the axis. But yes, you can customize the axis to whatever you need.
If you wish to have "1.0" labeled for either the min or max axis value, you can simply enter that value in at line 110 & 111. For example:
max_values(ii) = 1;
min_values(ii) = 0;
If you wish to have "1.0" labeled on the axis tick marks, the easiest way would be to solve for axes_interval integer and max and min limits that would display "1.0" as one of the tick marks.
Tracy Campbell (view profile)
Hi Moses,
Thank you for the help, that is exactly what I was looking for! I do have one followup question  is there a way to set specific numbers displayed on the axis? For example, I would like "1.0" to be labeled on all the axis.
Thanks again for any help!
Moses (view profile)
Hi Tracy, if you need the same axis you can change line the code at 110 & 111 from
max_values(ii) = max(group_points);
min_values(ii) = min(group_points);
to
max_values(ii) = max(max(P));
min_values(ii) = min(min(P));
Moses (view profile)
Sorry, there is a typo in the thread below, it should read
max_values(ii) = max(max(P));
min_values(ii) = min(min(P));
Moses (view profile)
Hi Tracy,
Do you need a user defined or a data based min and max for the axis limits?
Tracy Campbell (view profile)
Hi Moses,
Is there a quick edit I could do in order to set all axis to be the same length?
Thanks for the help!
Moses (view profile)
Hello Soham,
Thank you for the suggestions. I actually had this feature in previous versions, but removed it for some reason that I can't seem to remember now.
Yes, there is a simple way to do this. Just change line 110 from:
max_values(ii) = max(group_points);
to
max_values(ii) = max(max(P));
And it should scale everything to the maximum value of all the values.
Soham Choudhury (view profile)
Hello, Thank you for sharing the plot. For me it is the best way to show a spider/radar plot. However I have a small doubt regarding setting the ranges for the individual axes. Consider that I have 4 data values (dimension of P is 4x4) but the maximum range of these matrices are not the same, however I want the plot to be scaled according to the maximum of all the values. For example, if P(:,1) = [3 0 0 0] and P(:,2) = [0 1 5 1] , then I want 5 to be the maximum value of the 1st column as well. and the plot to be rescaled accordingly.
Can you tell me how to do that? It will help me out a lot.
Thank You.
Moses (view profile)
Also Virginia, one thing to note is that the spider plot will currently display only increasing values radially out, even for negative values. I might add an option to reverse this in future revisions.
Moses (view profile)
Hi Virginia,
Thank you for catching this. I have corrected the issue in the latest update. There is only one function now, as I think have multiple axes is more useful. Please let me know if there are any more issues.
Virginia Vannucci (view profile)
Hi, thank you for sharing your work!
How can I change polar axes limits in your spider_plot_multi_axis ? I would have negative values of the radius in the polar plot. Using Matlab function polarplot, I only have to add rlim to adjust the raxis limit to include negative values, but this solution doesn't work in your function. How can I solve this problem?
Thank you!
Moses (view profile)
Hi Christian,
I am glad that you were able to make it work. Just out of curiosity though, was it a problem with the pol2cart? Gabriela mentioned some problems with it in the comments below and suggested a solution.
Christian (view profile)
after some little changes (I am using 2015a) it works fine :)
Christian (view profile)
Hello,
I am trying to run your algorithm.
However it does not work and I also do not understand following:
% Polar points
radius = [0; axes_limit];
theta = 0:polar_increments:2*pi;
% Convert polar to cartesian coordinates
[x_axes, y_axes] = pol2cart(theta, radius);
This cannot work. (Different size)
Feedback is appreciated :)
Moses (view profile)
Hi Antonia,
Yes, running the code as displayed below will not work. What you need to do is to save the function (spider_plot.m) and the example script in the overview above into separate files. If the function and the example script are separately saved in the same directory, it should work. If you want the function to be saved to a different directory, you will need to save the folder path under the "Set Path" button in the "Home" ribbon panel.
Antonia (view profile)
Hi,
yes, this is exactly what I did.
This is the matlabcode I'm executing:
function spider_plot(P, P_labels, axes_interval, varargin)
% Create a spider web or radar plot
%
% spider_plot(P, P_labels, axes_interval) creates a spider web plot using
% the points specified in the array P. The column of P contains the data
% points and the rows of P contain the multiple sets of data points.
% Each point must be accompanied by a label specified in the cell
% P_labels. The number of intervals that separate the axes is specified
% by axes_interval.
%
% P  [vector  matrix]
% P_labels  [cell of strings]
% axes_interval  [integer]
%
% spider_plot(P, P_labels, axes_interval, line_spec) works the same as
% the function above. Additional line properties can be added in the
% same format as the default plot function in MATLAB.
%
% line_spec  [character vector]
%
%
% %%%%%%%%%%%%%%%%%%% Example of a Generic Spider Plot %%%%%%%%%%%%%%%%%%%
% Clear workspace
close all;
clearvars;
clc;
% Point properties
num_of_points = 6;
row_of_points = 4;
P = rand(row_of_points, num_of_points);
% Create generic labels
P_labels = cell(num_of_points, 1);
for ii = 1:num_of_points
P_labels{ii} = sprintf('Label %i', ii);
end
% Figure properties
figure('units', 'normalized', 'outerposition', [0 0.05 1 0.95]);
% Axes interval
axes_interval = 4;
% Spider plot
spider_plot(P, P_labels, axes_interval,...
'Marker', 'o',...
'LineStyle', '',...
'LineWidth', 2,...
'MarkerSize', 5);
% Title properties
title('Sample Spider Plot',...
'Fontweight', 'bold',...
'FontSize', 12);
% Legend properties
legend('show', 'Location', 'southoutside');
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Point Properties %%%
% Number of points
[num_of_rows, num_points] = size(P);
%%% Polar Axes %%%
% Polar increments
polar_increments = 2*pi/num_points;
% Calculate max limit of axes
max_value = max(max(P));
axes_limit = ceil(max_value*10)/10;
% Polar points
radius = [0; axes_limit];
theta = 0:polar_increments:2*pi;
% Convert polar to cartesian coordinates
[x_axes, y_axes] = pol2cartvect(theta, radius);
% Plot polar axes
grey = [1, 1, 1] * 0.5;
h = line(x_axes, y_axes,...
'LineWidth', 1,...
'Color', grey);
% Iterate through all the line handles
for ii = 1:length(h)
% Remove polar axes from legend
h(ii).Annotation.LegendInformation.IconDisplayStyle = 'off';
end
%%% Polar Isocurves %%%
% Incremental radius
radius = (0:axes_limit/axes_interval:axes_limit)';
% Convert polar to cartesian coordinates
[x_isocurves, y_isocurves] = pol2cartvect(theta, radius);
% Plot polar isocurves
hold on;
h = plot(x_isocurves', y_isocurves',...
'LineWidth', 1,...
'Color', grey);
% Iterate through all the plot handles
for ii = 1:length(h)
% Remove polar isocurves from legend
h(ii).Annotation.LegendInformation.IconDisplayStyle = 'off';
end
%%% Data Points %%%
% Iterate through all the rows
for ii = 1:num_of_rows
% Convert polar to cartesian coordinates
[x_points, y_points] = pol2cartvect(theta(1:end1), P(ii, :));
% Make points circular
x_circular = [x_points, x_points(1)];
y_circular = [y_points, y_points(1)];
% Plot data points
plot(x_circular, y_circular, varargin{:});
end
%%% Axis Properties %%%
% Figure background
fig = gcf;
fig.Color = 'white';
% Iterate through the isocurve radius
for ii = 1:length(radius)
% Display axis text for each isocurve
text(x_isocurves(ii, 1), 0, sprintf('%3.1f', radius(ii)),...
'Units', 'Data',...
'Color', 'black',...
'FontSize', 10,...
'HorizontalAlignment', 'center',...
'VerticalAlignment', 'middle');
end
% Label points
x_label = x_isocurves(end, :);
y_label = y_isocurves(end, :);
% Check if labels equals the number of points
if length(P_labels) == num_points
% Iterate through each label
for ii = 1:num_points
% Angle of point in radians
theta_point = theta(ii);
% Find out which quadrant the point is in
if theta_point == 0
quadrant = 0;
elseif theta_point == pi/2
quadrant = 1.5;
elseif theta_point == pi
quadrant = 2.5;
elseif theta_point == 3*pi/2
quadrant = 3.5;
elseif theta_point == 2*pi
quadrant = 0;
elseif theta_point > 0 && theta_point < pi/2
quadrant = 1;
elseif theta_point > pi/2 && theta_point < pi
quadrant = 2;
elseif theta_point > pi && theta_point < 3*pi/2
quadrant = 3;
elseif theta_point > 3*pi/2 && theta_point < 2*pi
quadrant = 4;
end
% Adjust text alignment information depending on quadrant
switch quadrant
case 0
horz_align = 'left';
vert_align = 'middle';
case 1
horz_align = 'left';
vert_align = 'bottom';
case 1.5
horz_align = 'center';
vert_align = 'bottom';
case 2
horz_align = 'right';
vert_align = 'bottom';
case 2.5
horz_align = 'right';
vert_align = 'middle';
case 3
horz_align = 'right';
vert_align = 'top';
case 3.5
horz_align = 'center';
vert_align = 'top';
case 4
horz_align = 'left';
vert_align = 'top';
end
% Display text label
text(x_label(ii), y_label(ii), P_labels{ii},...
'Units', 'Data',...
'HorizontalAlignment', horz_align,...
'VerticalAlignment', vert_align,...
'EdgeColor', 'k',...
'BackgroundColor', 'w');
end
else
% Error message
error('Error: Please make sure the number of labels is the same as the number of points.');
end
% Axis limits
axis square;
axis([axes_limit, axes_limit, axes_limit, axes_limit]);
axis off;
end
% 
function [x,y,z] = pol2cartvect(th,r,z)
if size(th,1) == size(r,1) && size(th,2) == size(r,2)
x = r.*cos(th); y = r.*sin(th);
else
x = r*cos(th); y = r*sin(th);
end
end
% 
Thank you very much !
Moses (view profile)
Hi Antonia,
I just tested it on Matlab R2017a as well, and it seems to work fine. Did you try the example code in the overview above with it uncommented (remove the % symbol using select all, Ctrl + A, and uncomment, Ctrl + T)?
Antonia (view profile)
Hi Moses,
thank you for sharing your work. One question left: I tried to use it with Matlab Version 2017a, it is not working as is does not stop running (so there's no error message). I replaced the pol2cart by pol2cartvect. Do you have any idea why it is not working?
Thank you!
Gabriela Andrade (view profile)
Hi Moses,
first of all, thanks for sharing this amazing work.
The pol2cart function was indeed in the core libraries for the versions I tried (20142016b), but it didn't work properly for vectors (that same old issue between different matlab versions, I suppose).
Feel free to include the pol2cartvect in the pack of files if you feel like.
Cheers!
Moses (view profile)
Hello Stefano, I added a separate function to display the axes for each parameter. Please try it out and let me know what you think. Thanks.
Moses (view profile)
Hi Stefano, I apologize but currently this spider plot does not support a range axes for each parameter. I intentionally left out that feature as the axes labels became too crowded. Instead I got around this issue by normalizing all of the data into units of percent.
I may end up updating this function to support a range axes for each parameter in the future, but for now I recommend that you try out the spider function by Michael Arant.
Best regards.
Stefano Anzilotti (view profile)
Hi, Moses. Your Plot is amazing and I would like to use it. I need to change the range axes for each parameter, can you help me? thank you in advance
Moses (view profile)
Hi BuMatlab,
Sorry, I assumed that the pol2cart function was part of the core matlab libraries, but I might have been mistaken.
https://www.mathworks.com/help/matlab/ref/pol2cart.html
Please insert Gabriela's function at the very end as a subfuction and replace all instances of pol2cart (ctrl + f, and replace) with pol2cartvect.
BuMatlab (view profile)
Gabriela  where do you insert the function that you create?
Gabriela Andrade (view profile)
Hi Miguel,
Try this:
Replace all the calls to "pol2cart" in the code by "pol2cartvect" and create this new function as follows:
% 
function [x,y,z] = pol2cartvect(th,r,z)
if size(th,1) == size(r,1) && size(th,2) == size(r,2)
x = r.*cos(th); y = r.*sin(th);
else
x = r*cos(th); y = r*sin(th);
end
% 
that might work.
Cheers!
Miguel Chavez (view profile)
Hello, your example is giving error also on Matlab R2015b. Could you check it? Thank you!
Moses (view profile)
Hi sz, I'm glad it could of good use. Also, one thing to keep in mind is that the data may need to be normalized if you want it in units of percent.
sz l (view profile)
sorry,I found it!it is a nice plot!help a lot!
sz l (view profile)
would you mind my asking for an example,thank you!
Moses (view profile)
Hi Esin, do you happen to know what the error message is? I just tested on Matlab R2016b and it seems to work fine.
Esin Karahan (view profile)
Hello, your example is giving error on Matlab R2015a. Could you check it? Thank you!