Versions that use the GitHub default branch cannot be downloaded

9.0

-Added support for adjust the axes offset from origin.
-Allow for one data group without specified axes limits.
-Added support for changing axes and label font type.

6.3

-Fix bug in reverse axes direction feature to properly display data points.

6.2

Adjust axes precision to be set to one or more axis.

6.1

Fix legend feature with inherited legend class in spider_plot_class().

6.0

-Updated all functions to have the same functionality.
-Added ability to reverse axes limits.
-Fixed bug in spider_plot_class() that prevented axes limits from updating properly.
-Updated live script examples.

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.
-Added support of log scale for negative numbers as well.

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.
-Add customization option for font sizes.

4.1

Minor revision to add name-value pairs for customizing color, marker, and line settings.

4.0

-Another major revision converting varargin arguments to name-value 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.

-Fixed to correctly display negative numbers.
-Added option to change the decimal precision on axes.
-The plot values now start from the first axes interval, not the origin, for clarity purposes.
-Error checking added.

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_class() is compatible with R2019b and above. It uses the new chart class feature.

Hi Marie-Kristin,
Thanks for the feature suggestion! I updated the function to allow the "FillOption" and "FillTransparency" to now be customizable to each data group.
You can refer to the example below or example #3.
%%% Example %%%
D1 = [5 3 9 1 2];
D2 = [5 8 7 2 9];
D3 = [8 2 1 4 6];
P = [D1; D2; D3];
s = spider_plot_class(P);
s.AxesLabels = {'S1', 'S2', 'S3', 'S4', 'S5'};
s.AxesInterval = 2;
s.FillOption = {'on', 'on', 'off'};
s.FillTransparency = [0.2, 0.1, 0.1];

Hi Moses,
Thanks for the correction.
I have a question about the plot: Is there a way to have the minimum value be the center of the spider chart instead of the first rho?

The implementations error out if the user does not specify the AxesLimits in the call.

>> s = spider_plot_class([1.2500 1.6667 2.5000 0 2.3333 0.5000]);
Error using spider_plot_class/get.AxesLimits (line 603)
Error: For one data group, please enter in a range for the axes limits.

Error in spider_plot_class/initialize (line 894)
if ~isempty(obj.AxesLimits)

Error in spider_plot_class/update (line 802)
initialize(obj);

Error in matlab.graphics.chart.internal.ChartBaseProxy/doUpdateInternal

Error in matlab.graphics.chart.internal.ChartBaseProxy/doUpdateChart

Hi Cedric,
The functions have been updated to allow adjusting the font. You can now use the 'AxesFont' and 'LabelFont' name-value pair to change the font.
Just a reminder that you can check the fonts you have on your system by typing in "d = listfonts" in the console.
Thanks!

Hi Nicolai, thank you for finding that bug! The functions have been updated to properly display the data points when the axis is reversed.
Yes, you can set the legend position to any position using the "LegendHandle.Location" argument. You can refer to the example below as well.

there seems to be an issue with the reversed axis. The axis tick labels are displayed correctly (e.g. in revers direction) but the data points (marker) are not at the correct position. I hope that this can easily be fixed.

Another question: is it possible to set the legend position (e.g. "southoutside")?

Hi Nicolai, that is a great idea! I updated all the functions to support setting the axes precision individually. Please refer to the updated example #2. Thanks for all the feature suggestions.

Is it also possible to set the precision for each axes individually? The benefit of a spider plot is that you can combine axes with different scales. One Axes could be from 0 to 1 and another from 10 to 100 and thus different precisions would be amazing.

Hi Nicolai, thank you for reporting that bug. The legend feature should now work in the spider_plot_class(). Please refer to the updated example #1. Thanks.

Hi Nicolai, regarding the spider_plot_R2019b_class:
1) Currently reversing a specific axis direction is not implemented. I think your feedback is a good feature to add in the next version.
2) Thank you for bringing that bug to attention. I will look to test the spider_plot_R2019b_class more robustly.
In the meantime, please use the spider_plot() function.
Thanks!

First of all thank you for your great work. I have two questions regarding the spider_plot_R2019b_class:
1) is it possible to reverse a specific axis direction?
2) setting the axis limits seems to have no effect but works for spider_plot. Is this intended?

The spider_plot_R2019b_class has a bug concerning axes limit, display and interval: In the function initialize(obj) in the case of linear axes scaling those properties are reset to default values. This renders the set-functions of those properties useless.

Hi Paula, just to clarify, do you mean your dataset has values <1 and so you would like to adjust the axes tick marks to show in intervals of 0.1 or 0.05?

Currently, the "AxesInterval" option specifies the number of webs and not the desired interval values.
So by adjusting the "AxesInterval" with "AxesLimits" you can adjust the interval values.

For example, if I want interval values of 0.05 on one axes and interval values of 0.1 on the others, I can do something like this:
%%%%%%%%%%%%%
D1 = [0.5 0.3 0.9 0.1 0.5];
D2 = [0.5 0.8 0.7 0.2 0.3];
D3 = [0.8 0.2 0.1 0.4 0.1];
P = [D1; D2; D3];
spider_plot(P,...
'AxesInterval', 10,...
'AxesLimits', [0, 0, 0, 0, 0; 1, 1, 1, 1, 0.5],...
'AxesPrecision', 2);
%%%%%%%%%%%%%%%%%%%%%

As you can see, you can set each axes limits individually to get the interval scaling that you want depending on your data.

Hi Moses, thanks for the function, it is really helpful.
One question, is it possible to adjust the code to have the AxesInterval in 0.1, 0.05? Using only integer does not work my dataset.

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.

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

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]);
======================================

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.

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.

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);

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.

Hi, thanks for this very useful function!
A small thing - the function appears to plot inputs anticlockwise (for P1-x). Is it possible to plot them clockwise?

Hi Matteo,
I updated the code to make color, marker, and line settings into name-value pair arguments. If you'd like, please download the latest version and see the examples.
Thanks,
Moses

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.

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.

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

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 out-of-range 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

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:

[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_limit-P(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

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.

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 110-111 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.

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');

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.

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.

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.

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

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)

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 ;)

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.

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

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.

Thank you for the help, that is exactly what I was looking for! I do have one follow-up 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.

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.

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.

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.

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 r-axis limit to include negative values, but this solution doesn't work in your function. How can I solve this problem?
Thank you!

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.

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 :)

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.

Hi,
yes, this is exactly what I did.
This is the matlab-code 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);

% Iterate through all the line handles
for ii = 1:length(h)
% Remove polar axes from legend
h(ii).Annotation.LegendInformation.IconDisplayStyle = 'off';
end

% 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:end-1), P(ii, :));

% 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

% 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

% ----------
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

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 un-commented (remove the % symbol using select all, Ctrl + A, and uncomment, Ctrl + T)?

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?

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 (2014-2016b), 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!

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.

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
% ----------

You can also select a web site from the following list:

How to Get Best Site Performance

Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.

ahmed shahinThanks Alot Moses

MosesHello Ahmed, you can achieve that by adjusting the "AxesDisplay" and "AxesInterval" settings.

%%% Example %%%

D1 = [5 3 9 1 2];

D2 = [5 8 7 2 9];

D3 = [8 2 1 4 6];

P = [D1; D2; D3];

spider_plot(P,...

'AxesDisplay', 'none',...

'AxesInterval', 1);

ahmed shahinhello sir

thanks aot for your excellent library

and i have a question please

how to cancel displaying all numbers on axes

axes interval to zero

Dave HoadleyVery cool work

michioMarie-Kristin SchreiberThanks Moses for the fast realisation. Great!

MosesHi Marie-Kristin,

Thanks for the feature suggestion! I updated the function to allow the "FillOption" and "FillTransparency" to now be customizable to each data group.

You can refer to the example below or example #3.

%%% Example %%%

D1 = [5 3 9 1 2];

D2 = [5 8 7 2 9];

D3 = [8 2 1 4 6];

P = [D1; D2; D3];

s = spider_plot_class(P);

s.AxesLabels = {'S1', 'S2', 'S3', 'S4', 'S5'};

s.AxesInterval = 2;

s.FillOption = {'on', 'on', 'off'};

s.FillTransparency = [0.2, 0.1, 0.1];

Marie-Kristin SchreiberHi! Thanks for the spider plot at all. Do you see a possibility to have only a several amount of plots filled and some without filling?

Cedric JametSorry, just saw the update.

Thanks for this great function

Richard RuffHi Moses,

Thanks for the update and the quick response. This does exactly what I want.

MosesHi Richard,

Yes, I updated the function to allow the spider chart to start at any rho integer between [0, AxesInterval]. Below is an example.

%%% Example %%%

s = spider_plot_class([1.2500 1.6667 2.5000 0 2.3333 0.5000]);

s.AxesOffset = 0;

s.AxesPrecision = 2;

Thanks for all the useful feature requests!

Richard RuffHi Moses,

Thanks for the correction.

I have a question about the plot: Is there a way to have the minimum value be the center of the spider chart instead of the first rho?

MosesHi Richard,

Thank you for pointing out that error. The function has been updated to allow one data group without a specified AxesLimit.

Thanks!

Richard RuffThe implementations error out if the user does not specify the AxesLimits in the call.

>> s = spider_plot_class([1.2500 1.6667 2.5000 0 2.3333 0.5000]);

Error using spider_plot_class/get.AxesLimits (line 603)

Error: For one data group, please enter in a range for the axes limits.

Error in spider_plot_class/initialize (line 894)

if ~isempty(obj.AxesLimits)

Error in spider_plot_class/update (line 802)

initialize(obj);

Error in matlab.graphics.chart.internal.ChartBaseProxy/doUpdateInternal

Error in matlab.graphics.chart.internal.ChartBaseProxy/doUpdateChart

Richard RuffThe error occurs in R2020A and R2019B. It also occurs when running some of the examples.

MosesHi Cedric,

The functions have been updated to allow adjusting the font. You can now use the 'AxesFont' and 'LabelFont' name-value pair to change the font.

Just a reminder that you can check the fonts you have on your system by typing in "d = listfonts" in the console.

Thanks!

Cedric JametHi Moses,

Thank you very much for this function.

I don't get how to change the font of the axes labels. I have been able to remove the box around them but I don't understand how to change the font.

Thanks

MosesHi Nicolai, thank you for finding that bug! The functions have been updated to properly display the data points when the axis is reversed.

Yes, you can set the legend position to any position using the "LegendHandle.Location" argument. You can refer to the example below as well.

%%% Example %%%

D1 = [5 3 9 1 2];

D2 = [5 8 7 2 9];

D3 = [8 2 1 4 6];

P = [D1; D2; D3];

s = spider_plot_class(P);

s.AxesDirection = {'reverse', 'normal', 'reverse', 'normal', 'reverse'};

s.LegendLabels = {'D1', 'D2', 'D3'};

s.LegendHandle.Location = 'southoutside';

NicolaiHello Moses,

there seems to be an issue with the reversed axis. The axis tick labels are displayed correctly (e.g. in revers direction) but the data points (marker) are not at the correct position. I hope that this can easily be fixed.

Another question: is it possible to set the legend position (e.g. "southoutside")?

thanks a lot,

Nico

Jingwei TooNice toolbox

Jingwei TooI have found a way to do it. Thank you

MosesHi Nicolai, that is a great idea! I updated all the functions to support setting the axes precision individually. Please refer to the updated example #2. Thanks for all the feature suggestions.

NicolaiHello Moses,

It's me again :)

Is it also possible to set the precision for each axes individually? The benefit of a spider plot is that you can combine axes with different scales. One Axes could be from 0 to 1 and another from 10 to 100 and thus different precisions would be amazing.

As always thanks a lot. Great Job!

MosesHi Nicolai, thank you for reporting that bug. The legend feature should now work in the spider_plot_class(). Please refer to the updated example #1. Thanks.

NicolaiHello Moses,

the updated version works great: setting axis limits and reversing the axis direction is now possible in spider_plot_class!

One more question: is it possible to set the Legend Location and Orientation?

Many thanks in advance!!!

Nico

MosesHi Nicolai, regarding the spider_plot_R2019b_class:

1) Currently reversing a specific axis direction is not implemented. I think your feedback is a good feature to add in the next version.

2) Thank you for bringing that bug to attention. I will look to test the spider_plot_R2019b_class more robustly.

In the meantime, please use the spider_plot() function.

Thanks!

NicolaiHello Moses,

First of all thank you for your great work. I have two questions regarding the spider_plot_R2019b_class:

1) is it possible to reverse a specific axis direction?

2) setting the axis limits seems to have no effect but works for spider_plot. Is this intended?

Thank you!

Nico

MosesHi Marius, thank you for reporting the bug. I will look to fix it in the next update. In the meantime, please use the spider_plot() function.

Thanks.

Marius MuellerHi Moses,

first of all great work!

The spider_plot_R2019b_class has a bug concerning axes limit, display and interval: In the function initialize(obj) in the case of linear axes scaling those properties are reset to default values. This renders the set-functions of those properties useless.

MosesHi Paula, just to clarify, do you mean your dataset has values <1 and so you would like to adjust the axes tick marks to show in intervals of 0.1 or 0.05?

Currently, the "AxesInterval" option specifies the number of webs and not the desired interval values.

So by adjusting the "AxesInterval" with "AxesLimits" you can adjust the interval values.

For example, if I want interval values of 0.05 on one axes and interval values of 0.1 on the others, I can do something like this:

%%%%%%%%%%%%%

D1 = [0.5 0.3 0.9 0.1 0.5];

D2 = [0.5 0.8 0.7 0.2 0.3];

D3 = [0.8 0.2 0.1 0.4 0.1];

P = [D1; D2; D3];

spider_plot(P,...

'AxesInterval', 10,...

'AxesLimits', [0, 0, 0, 0, 0; 1, 1, 1, 1, 0.5],...

'AxesPrecision', 2);

%%%%%%%%%%%%%%%%%%%%%

As you can see, you can set each axes limits individually to get the interval scaling that you want depending on your data.

Hope that answers your question.

Paula GodoyHi Moses, thanks for the function, it is really helpful.

One question, is it possible to adjust the code to have the AxesInterval in 0.1, 0.05? Using only integer does not work my dataset.

Thanks in advance

Gábor RemzsoMosesHi 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 AbubakrHi 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.

MosesHi 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 SepczukHI,

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 Bettaniniyuqiang liHi Moses

Thank you for providing this great function.

From China.

MosesHi Roman, thank you for the feature suggestions! I will look to add it in the next update.

RomanHi 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

RomanIchechi WeliMosesHi 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 IgnacioChristophe HurlinThank 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.

MosesHello 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 AliWhen I add more than seven legends, it gives an error. For seven and less legends, it works fine. Please help me. Thank you

MosesHello 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 HadriCan 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');

....

MosesHi Tobias, yes, I've updated the function to allow for log-scaling on all axes. Please download the latest version and take a look at example #6.

Tobias KernHi Moses, first thanks for sharing this useful feature! I wanted to know if there is an easy option to implement a log-scaling on all axes?

MosesHi 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 GrenyerHi, thanks for this very useful function!

A small thing - the function appears to plot inputs anticlockwise (for P1-x). Is it possible to plot them clockwise?

cuivery nice! easy to use!

dongdong GengNice tool.

MosesHi Matteo,

I updated the code to make color, marker, and line settings into name-value pair arguments. If you'd like, please download the latest version and see the examples.

Thanks,

Moses

Matteo BilardoHi 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

MosesHi 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.

arnoldIs there a way to fill the inscribed polygon with a color, ideally with some transparency?

MosesHello 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 GarciaTo 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 out-of-range 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 GarciaAnd 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:

% Pre-allocation

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_limit-P(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 GarciaCareful! 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 GarciaHenry IpAllison MillerMosesHi 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 110-111 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 leguebehello 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');

MosesHi 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/152217-ismember-legacy-flag-with-older-matlab

https://stackoverflow.com/questions/20494721/matlab-bug-in-ismember

and for the IdleTimeout error, please check the following:

https://www.mathworks.com/matlabcentral/answers/179509-parallel-programming-toolbox-shutting-down

https://www.mathworks.com/matlabcentral/answers/410692-parallel-pool-shut-down-during-the-iteration

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 KongHi 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?

MosesHi 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.

JakobHi 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?

MosesHi 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 RuferDear 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 StewartThanks for this

Chunhui ZhuHi 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)

MosesHi Freya,

Thank you for catching that typo in the description. I will correct it in the next version released.

Freya HHi 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 DEMBELEI finally used the pol2cartvect function of Gabriela and it's working. Thanks!

MosesHi 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/218422-how-to-get-rid-of-the-error-message-set-0-recursionlimit-n

https://www.mathworks.com/matlabcentral/answers/242157-errors-when-using-close-or-close-all

In the article, the function unique.m was causing the error, but depending on your code it may be a different function name.

Daniel NgHi 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 dengMosesHi 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 CampbellHi Moses,

Thank you for the help, that is exactly what I was looking for! I do have one follow-up 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!

MosesHi 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));

MosesSorry, there is a typo in the thread below, it should read

max_values(ii) = max(max(P));

min_values(ii) = min(min(P));

MosesHi Tracy,

Do you need a user defined or a data based min and max for the axis limits?

Tracy CampbellHi Moses,

Is there a quick edit I could do in order to set all axis to be the same length?

Thanks for the help!

MosesHello 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 ChoudhuryHello, 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.

MosesAlso 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.

MosesHi 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 VannucciHi, 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 r-axis limit to include negative values, but this solution doesn't work in your function. How can I solve this problem?

Thank you!

MosesHi 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.

Christianafter some little changes (I am using 2015a) it works fine :)

ChristianHello,

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 :)

MosesHi 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.

AntoniaHi,

yes, this is exactly what I did.

This is the matlab-code 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:end-1), 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 !

MosesHi 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 un-commented (remove the % symbol using select all, Ctrl + A, and uncomment, Ctrl + T)?

AntoniaHi 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 AndradeHi Moses,

first of all, thanks for sharing this amazing work.

The pol2cart function was indeed in the core libraries for the versions I tried (2014-2016b), 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!

MosesHello 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.

MosesHi 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 AnzilottiHi, 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

MosesHi 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.

BuMatlabGabriela - where do you insert the function that you create?

Gabriela AndradeHi 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 ChavezHello, your example is giving error also on Matlab R2015b. Could you check it? Thank you!

MosesHi 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 lsorry,I found it!it is a nice plot!help a lot!

sz lwould you mind my asking for an example,thank you!

MosesHi Esin, do you happen to know what the error message is? I just tested on Matlab R2016b and it seems to work fine.

Esin KarahanHello, your example is giving error on Matlab R2015a. Could you check it? Thank you!