Matlab scatter and histogram plot - matlab

I have 20 numerical data points with x and y coordinates. I would like to plot them in a 2D plot. They will be concentrated around an x and y coordinate. To better visualise this behaviour, I would like to add histogram bars on top of the 2D scatter plot for the x axis, and histogram bars on the right of the 2D plot for the y axis this way, they do not interfere with the axis labels. Now, my 20 numerical points are in fact two sets of 10 and I would like to have both sets plotted in different colours. Something like this:
python plot
How can I do this?
Update:
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
minx = min([FWHM11Avg; FWHM11Med]);
maxx = max([FWHM11Avg; FWHM11Med]);
miny = min([FWHM12Avg; FWHM12Med]);
maxy = max([FWHM12Avg; FWHM12Med]);
% make figure
figure(1)
clf
% first subplot -- y-data histc
ah1 = subplot(2, 2, 1);
y_bins = 1.5:.25:4.5;
n = hist(FWHM12Avg, y_bins);
bar(y_bins, n, 'vertical', 'on')
hold on
hist(FWHM12Med, y_bins)
bar(y_bins, n, 'vertical', 'on')
% x-data histc
ah2 = subplot(2, 2, 4);
x_bins = 1.5:.25:4.5;
n = hist(FWHM11Avg, x_bins);
bar(x_bins, n, 'horizontal', 'on')
hold on
n = hist(FWHM11Med, x_bins);
bar(x_bins, n, 'horizontal', 'on')
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(FWHM11Avg, FWHM11Med)
scatter(FWHM12Avg, FWHM12Med)
% link axes, adjust histc orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
set(ah3,'XLim',[minx, maxx]);
set(ah3,'YLim',[miny, maxy]);
ah1.Box = 'off';
ah1.View = [180, -90];
ah1.Visible = 'off';
ah2.Visible = 'off';
ah2.Box = 'off';
ah2.View = [0, -90];
Also there seems not to be an option available for adding numerical axes to the histograms to see how many points there are in a bar - at least in the documentation I did not see any option. Is that so?
Second Update with applied suggestions to the above syntax:
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
minx = min([FWHM11Avg; FWHM11Med]);
maxx = max([FWHM11Avg; FWHM11Med]);
miny = min([FWHM12Avg; FWHM12Med]);
maxy = max([FWHM12Avg; FWHM12Med]);
% make figure
figure(1)
clf
% first subplot -- y-data histc
ah1 = subplot(2, 2, 1);
y_bins = 1.5:.25:4.5;
n = hist(FWHM12Avg, y_bins);
bar(y_bins, n, 'vertical', 'on')
hold on
hist(FWHM12Med, y_bins)
bar(y_bins, n, 'vertical', 'on')
% x-data histc
ah2 = subplot(2, 2, 4);
x_bins = 1.5:.25:4.5;
n = hist(FWHM11Avg, x_bins);
bar(x_bins, n, 'horizontal', 'on')
hold on
n = hist(FWHM11Med, x_bins);
bar(x_bins, n, 'horizontal', 'on')
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(FWHM11Avg, FWHM11Med)
scatter(FWHM12Avg, FWHM12Med)
% link axes, adjust histc orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
set(ah3,'XLim',[minx, maxx]);
set(ah3,'YLim',[miny, maxy]);
set(ah1,'Box','off');
set(ah1,'View',[180, -90]);
set(ah1,'Visible','off');
set(ah2,'Visible','off');
set(ah2,'Box','off');
set(ah2,'View',[0, -90]);

Please research before asking. There is a function in Matlab scatterhist which does this
x0 = 6.1;
y0 = 3.2;
n = 50;
r = rand(n ,1 );
theta = 2*pi*rand(n, 1);
x = x0 + r.*cos(theta);
y = y0 + r.*sin(theta);
scatterhist(x,y, 'Direction','out', 'Location', 'NorthEast')
Edit: Using the data you provided. Is this what you want?
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
% make figure
figure(1)
clf
FWHM11Avg = FWHM11Avg(:);
FWHM11Med = FWHM11Med(:);
FWHM12Avg = FWHM12Avg(:);
FWHM12Med = FWHM12Med(:);
minX = min([FWHM11Avg; FWHM12Avg]);
maxX = max([FWHM11Avg; FWHM12Avg]);
minY = min([FWHM11Med; FWHM12Med]);
maxY = max([FWHM11Med; FWHM12Med]);
resX = 0.25;
resY = 0.25;
nBinsX = ceil((maxX - minX) / resX);
nBinsY = ceil((maxY - minY) / resY);
label = vertcat( ...
num2cell(repmat('FWHM11', size(FWHM11Avg)),2), ...
num2cell(repmat('FWHM12', size(FWHM11Avg)),2));
Avg = vertcat(FWHM11Avg, FWHM12Avg);
Med = vertcat(FWHM11Med, FWHM12Med);
% scatterplot
scatterhist(Avg, Med, 'Group', label, 'Direction','out', ...
'Location', 'NorthEast', 'NBins', [nBinsX, nBinsY])

This is something I've been using lately:
% generate some random data
mu = [1 2];
sigma = [1 0.5; 0.5 2];
R = chol(sigma);
my_data1 = repmat(mu,100,1) + randn(100,2)*R;
mu = [2 1];
sigma = [3 -0.5; -0.5 2];
R = chol(sigma);
my_data2 = repmat(mu,100,1) + randn(100,2)*R;
% find limits
minx = min([my_data1(:, 1); my_data2(:, 1)]);
maxx = max([my_data1(:, 1); my_data2(:, 1)]);
miny = min([my_data1(:, 2); my_data2(:, 2)]);
maxy = max([my_data1(:, 2); my_data2(:, 2)]);
% make figure
figure(1)
clf
% first subplot -- y-data histogram
ah1 = subplot(2, 2, 1);
histogram(my_data1(:, 2), 'Orientation','horizontal', 'Normalization', 'probability', 'BinWidth', 0.5)
hold on
histogram(my_data2(:, 2), 'Orientation','horizontal', 'Normalization', 'probability', 'BinWidth', 0.5)
% x-data histogram
ah2 = subplot(2, 2, 4);
histogram(my_data1(:, 1), 'Normalization', 'probability', 'BinWidth', 0.5)
hold on
histogram(my_data2(:, 1), 'Normalization', 'probability', 'BinWidth', 0.5)
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(my_data1(:, 1), my_data1(:, 2))
scatter(my_data2(:, 1), my_data2(:, 2))
% link axes, adjust histogram orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
ah3.XLim = [minx, maxx];
ah3.YLim = [miny, maxy];
ah1.Box = 'off';
ah1.View = [180, -90];
ah1.Visible = 'off';
ah2.Visible = 'off';
ah2.Box = 'off';
ah2.View = [0, -90];
producing this plot
This code assumes a recent version of MATLAB (I use 2014b), but can be easily adapted using the old histogram functions (hist, histc) and the set(..) syntax for graphical objects.

Related

Rotate line to arbitary position around unit circle

I have a unit circle with n roots of unity marked. I would like to be able to rotate, translate, and scale a line resting on the x-axis (between -1 and 1) to connect any pair of marked roots. Currently my code can do this in some cases, but doesn't work in general. I want to avoid hard-coding how the line should move for each possible pair. Here's what I have so far:
clear
%% Roots of unity
n = 10;
roots = zeros(1, n);
for k = 1 : n
roots(k) = exp(2 * k* pi * 1i / n);
end
%% Move line
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
% Coordinates of pair of roots
x1 = real(point_1);
x2 = real(point_2);
y1 = imag(point_1);
y2 = imag(point_2);
d = sqrt((x1-x2)^2+(y1-y2)^2); % Euclidean distance between pair of roots
m = (y1 - y2) / (x1 - x2); % Gradient of line connecting pair of roots
c = y1 - m * x1; % y-intercept of line
int = -c / m; % x-coordinate that the rotation should occur at
shift = [int; 0];
x = linspace(-1, 1, 10); % Initial line lying purely on x-axis
y = 0 * x;
v = [x; y];
theta = atan((y2-shift(2))/(x2-shift(1))); % Angle by which to rotate
rot = [cos(theta), -sin(theta); sin(theta), cos(theta)]; % Rotation matrix
u = v * (d / 2); % Scale initial line
if m < 1e-3 % Horizontal case
shift = [0; 0];
end
w = (rot * (u - shift)) + shift; % Apply rotation
% Another shift that seems necessary
% This is definitely a problematic section
shift_x = w(1, 1) - x2;
shift_y = w(2, 1) - y2;
shift_2 = [shift_x; shift_y];
w = w - shift_2;
%% Plot
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
ax = gca;
tt = title(ax, 'Title');
tt.FontWeight = 'bold';
tt.FontSize = 20;
st = subtitle(ax, sprintf('More text here'));
st.FontAngle = 'italic';
st.FontSize = 15;
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
for i = 1 : n
x_point = real(roots(i));
y_point = imag(roots(i));
hPin = plot(x_point, y_point, 'Marker', 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
end
% Plot original and shifted line, split into colours so direction is easier to see
plot(v(1,1:4), v(2,1:4), 'b');
plot(v(1,4:7), v(2,4:7), 'r');
plot(v(1,7:end), v(2,7:end), 'g');
plot(w(1,1:4), w(2,1:4), 'b');
plot(w(1,4:7), w(2,4:7), 'r');
plot(w(1,7:end), w(2,7:end), 'g');
For example, keeping point_1 = roots(2); and changing only point_2 = roots(p); works as intended for only p=3, 4, 6, 7, 8.
Any guidance on how to get this working would be greatly appreciated, thanks!
Edit:
To give some more details, basically I have an array of numbers between 0 and 1 (rather than just a line) which I want to plot on the line that would connect two roots. E.g. if my array is x=[0.2, 0.5, 0.9], then I want three points between point_1 and point_2, the first being 0.2d down the connecting line away from point_1, the second 0.5d (i.e. halfway), and the final being 0.9d away.
First of all, since the points you want to connect are complex numbers, it is easier to work with complex coordinate directly.
Roots of unity
I have simplified your code a bit.
Some may raise a flag on naming a variable roots since roots is a built-in matlab function. I am fine with it, as long as the usage does not cause any confusion, namely, don't use roots as a variable and as a function in the same context.
As matlab provides so many built-in functions, it is impossible to avoid name collision unless one knows them all by heart or searches before naming every single variable.
n = 10;
k = 1:n;
roots = exp(2 * k * pi * 1i / n);
Scaling, rotating, and translating
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
d = abs(point_2 - point_1); % distance between pair of roots
theta = angle(point_2 - point_1); % rotation angle
p_on_line = linspace(-1, 1, 10); % Initial line lying on x-axis
p_on_line = p_on_line * d/2; % scale
p_on_line = p_on_line * exp(1i*theta); % rotate
p_on_line = p_on_line + (point_1 - p_on_line(1)); % translate
Plot
I added some scatter points and removed irrevelant parts (e.g. title, fonts).
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
hPin = plot(roots, 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
% Plot line connecting roots
plot(p_on_line(1:4), 'b.-', 'MarkerSize', 20);
plot(p_on_line(4:7), 'r.-', 'MarkerSize', 20);
plot(p_on_line(7:end), 'g.-', 'MarkerSize', 20);
% Plot original line
original_x = linspace(-1, 1, 10);
original_y = zeros(1, 10);
plot(original_x(1:4), original_y(1:4), 'b.-', 'MarkerSize', 20);
plot(original_x(4:7), original_y(4:7), 'r.-', 'MarkerSize', 20);
plot(original_x(7:end), original_y(7:end), 'g.-', 'MarkerSize', 20);
hold off
This should work for all combinations of root pairs.

Inscribe circle of an object rotated results - Matlab

I modified a code based on the shown in https://www.mathworks.com/matlabcentral/answers/377838-please-how-can-i-find-the-center-and-the-radius-of-the-inscribed-circle-of-a-set-of-points in order to find the inscribe circle but I do not understand why the image is rotated. Why and how can I solve it?
Code:
url='https://i.pcmag.com/imagery/reviews/00uaCVfzQ4Gsuhmh85WvT3x-4.fit_scale.size_1028x578.v_1569481686.jpg';
Image = rgb2gray(imread(url));
Image = imcomplement(Image);
fontSize = 10;
% determine contours
BW = imbinarize(Image);
BW = imfill(BW,'holes');
[B,L] = bwboundaries(BW,'noholes');
k = 1;
b = B{k};
y = b(:,2);
x = b(:,1);
subplot(2, 2, 1);
plot(x, y, 'b.-', 'MarkerSize', 3);
grid on;
title('Original Points', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0.04, 1, 0.96]);
% Make data into a 1000x1000 image.
xMin = min(x)
xMax = max(x)
yMin = min(y)
yMax = max(y)
scalingFactor = 1000 / min([xMax-xMin, yMax-yMin])
x2 = (x - xMin) * scalingFactor + 1;
y2 = (y - yMin) * scalingFactor + 1;
mask = poly2mask(x2, y2, ceil(max(y2)), ceil(max(x2)));
% Display the image.
p2 = subplot(2, 2, 2);
imshow(mask);
axis(p2, 'on', 'xy');
title('Mask Image', 'FontSize', fontSize);
% Compute the Euclidean Distance Transform
edtImage = bwdist(~mask);
% Display the image.
p3 = subplot(2, 2, 3);
imshow(edtImage, []);
axis(p3, 'on', 'xy');
% Find the max
radius = max(edtImage(:))
% Find the center
[yCenter, xCenter] = find(edtImage == radius)
% Display circles over edt image.
viscircles(p3, [xCenter, yCenter], radius,'Color','g');
% Display polygon over image also.
hold on;
plot(x2, y2, 'r.-', 'MarkerSize', 3, 'LineWidth', 2);
title('Euclidean Distance Transform with Circle on it', 'FontSize', fontSize);
% Display the plot again.
subplot(2, 2, 4);
plot(x, y, 'b.-', 'MarkerSize', 3);
grid on;
% Show the circle on it.
hold on;
% Scale and shift the center back to the original coordinates.
xCenter = (xCenter - 1)/ scalingFactor + xMin
yCenter = (yCenter - 1)/ scalingFactor + yMin
radius = radius / scalingFactor
rectangle('Position',[xCenter-radius, yCenter-radius, 2*radius, 2*radius],'Curvature',[1,1]);
title('Original Points with Inscribed Circle', 'FontSize', fontSize);
Original image:
Output image
[B,L] = bwboundaries(BW,...) returns in B the row and column values (documentation). That is, the first column of B{k} is y, the second one is x.
After changing this bit of code as follows:
y = b(:,1);
x = b(:,2);
you will notice that the image is upside down! That is because in an image the y-axis increases down (y is the row number in the matrix), whereas in the plot the y-axis increases up (mathematical coordinate system).
The axes where you use imshow in are automatically set to the right coordinate system, but then you do axis(p3, 'on', 'xy');, turning it upside down again. Instead, use
axis(p1, 'on', 'image');
on the axes where you don't use imshow (i.e. the top-left and bottom-right ones).

presenting motion of random walkers in matlab

I have simulated some random walkers. I used
plot(xb,yb,'b--o')
to show particles in each step. I saw a code in below link with beautiful particles with tail which moves in a blur way. Is there a way which I could my random walkers the same as the walkers in the link in mat lab? Could anyone tell me which should I use instead of the plot function I used?
beautiful particles
The code I tried:
clear all
close all
lbox=20;
%random fluctuation
eta = (2.*pi).*.1;
vs=0.02;
n=200;
birdl=[1:n];
axis([0 lbox 0 lbox])
axis('square')
hold on
xb=rand(n,1).*lbox; %first possition
yb=rand(n,1).*lbox; %first possition
vxb = 1;
vyb = 1;
for steps=1:5000;
xb = xb + vxb;
yb = yb+ vyb;
for bird1 = 1:n;
%periodic boundary condition
if(xb(bird1)<0);xb(bird1)=xb(bird1)+lbox; end
if (yb(bird1)<0);yb(bird1)=yb(bird1)+lbox;end
if (xb(bird1)>lbox);xb(bird1)=xb(bird1)-lbox;end
if (yb(bird1)>lbox);yb(bird1)=yb(bird1)-lbox;end
end
ang=eta.*(rand(n,1)-0.5);
vxb = vs.*cos(ang);
vyb = vs.*sin(ang);
cla
set(gcf,'doublebuffer','on')
plot(xb,yb,'.b')
%quiver(xb,yb,vxb,vyb,'b')
drawnow
end
If you want to create a sort of trail of where the particles have recently been, you can store the previous nStore plots and change their color so that older plots gradually darken and fade to black (alpha transparency like in your sample isn't possible with line objects in MATLAB). Here's a reworking of your code (with a few other improvements, like replacing the inner boundary condition loop with indexing):
clear all
close all
lbox = 20;
%random fluctuation
eta = (2.*pi).*1;
vs = 0.05;
n = 200;
set(gcf, 'doublebuffer', 'on', 'Color', 'k');
set(gca, 'Visible', 'off');
axis([0 lbox 0 lbox])
axis('square')
hold on
xb = rand(n, 1).*lbox; %first possition
yb = rand(n, 1).*lbox; %first possition
vxb = 1;
vyb = 1;
hList = [];
nStore = 30;
cMap = [zeros(nStore+1, 1) linspace(1, 0, nStore+1).' zeros(nStore+1, 1)];
for steps = 1:200
xb = xb + vxb;
yb = yb + vyb;
%periodic boundary condition
index = (xb < 0);
xb(index) = xb(index) + lbox;
index = (yb < 0);
yb(index) = yb(index) + lbox;
index = (xb > lbox);
xb(index) = xb(index) - lbox;
index = (yb > lbox);
yb(index) = yb(index) - lbox;
ang = eta.*(rand(n,1)-0.5);
vxb = vs.*cos(ang);
vyb = vs.*sin(ang);
h = plot(xb, yb, '.g', 'MarkerSize', 12);
if (numel(hList) == nStore)
delete(hList(nStore));
hList = [h hList(1:end-1)];
else
hList = [h hList];
end
set(hList, {'Color'}, num2cell(cMap(1:numel(hList), :), 2));
drawnow
end
And here's an animation:
I created the animation by adding the following code:
% After the drawnow...
frame = getframe(gca);
im = frame2im(frame);
imind(:, :, 1, steps) = uint8(rgb2ind(im, cMap, 'nodither'));
% After the loop...
imwrite(imind(:, :, 1, 1:2:end), cMap, 'randwalk.gif', ...
'Loopcount', Inf, 'DelayTime', 0);
I had to trim out some frames to make the gif smaller.
My shot at "nicer" random walk:
clear all
close all
lbox=20;
figure('Color',[0 0 0])
%random fluctuation
eta = (2.*pi).*1;
vs=0.02;
n=300;
birdl=[1:n];
axis([0 lbox 0 lbox])
axis('square')
hold on
xb=rand(n,1).*lbox; %first possition
yb=rand(n,1).*lbox; %first possition
vxb = 1;
vyb = 1;
for steps=1:5000;
xb = xb + vxb;
yb = yb+ vyb;
for bird1 = 1:n;
%periodic boundary condition
if (xb(bird1)<0);xb(bird1)=xb(bird1)+lbox; end
if (yb(bird1)<0);yb(bird1)=yb(bird1)+lbox;end
if (xb(bird1)>lbox);xb(bird1)=xb(bird1)-lbox;end
if (yb(bird1)>lbox);yb(bird1)=yb(bird1)-lbox;end
end
ang=eta.*(rand(n,1)-0.5);
vxb = vs.*cos(ang);
vyb = vs.*sin(ang);
cla
set(gca,'Color',[0 0 0]);
set(gcf,'doublebuffer','on')
set(gca,'YTick',[]);
set(gca,'XTick',[]);
plot(xb,yb,'.g','markersize',10)
% this should draw lines, but its slow and not as neat as a web app
% plot([xb xb-vxb*5]',[yb yb-vyb*5]','g')
drawnow
end

MATLAB - Approximating the integral with hemisphere domain with sample data

The integral part of the rendering equation performs an integral over a hemisphere range (with respect to solid angle).
I can generate samples that carry the value of corresponding integrand with this code:
n = 10;
rho_s = 0.5;
rho_d = 0.5;
light_phi = degtorad(30);
light_theta = degtorad(60);
[lx ly lz] = sph2cart(light_phi, light_theta, 1);
refDir = cat(3, -lx, -ly, lz);
normal = cat(3, 0, 0, 1);
[sample_phi sample_theta] = meshgrid(0:12:360, 0:3:90);
[sample_x sample_y sample_z] = sph2cart(degtorad(sample_phi), degtorad(sample_theta), 1);
viewDir = cat(3, sample_x, sample_y, sample_z);
dotRL = sum(bsxfun(#times, viewDir, refDir), 3);
dotRL = max(dotRL, 0);
brdf_s = rho_s*(n+2)*(dotRL.^n)/(2*pi);
brdf_d = rho_d/pi;
brdf = brdf_s + brdf_d;
x = sample_x.*brdf; y = sample_y.*brdf; z = sample_z.*brdf;
mesh(x, y, z);
line([0 lx],[0 ly],[0 lz]);
axis equal; axis vis3d;
xlim([-1 1]); ylim([-1 1]); zlim([0 1]);
The question I face now is how to do the integral or approximation with these samples?

How to plot a hyper plane in 3D for the SVM results?

I just wondering how to plot a hyperplane of the SVM results.
For example, here we are using two features, we can plot the decision boundary in 2D. But if how can we plot a hyperplane in 3D if we use 3 features?
load fisheriris;
features = meas(1:100,:);
featureSelcted = features(1:100,1:2); % For example, featureSelcted = features(1:100,1:3) can not be plotted
groundTruthGroup = species(1:100);
svmStruct = svmtrain(featureSelcted, groundTruthGroup, ...
'Kernel_Function', 'rbf', 'boxconstraint', Inf, 'showplot', true, 'Method', 'QP');
svmClassified = svmclassify(svmStruct,featureSelcted,'showplot',true);
A similar solution in R can be found at svm-fit-hyperplane, but a Matlab implementation would be handy.
Here is a function to plot 3D SVM results in MATLAB.
function [] = svm_3d_matlab_vis(svmStruct,Xdata,group)
sv = svmStruct.SupportVectors;
alphaHat = svmStruct.Alpha;
bias = svmStruct.Bias;
kfun = svmStruct.KernelFunction;
kfunargs = svmStruct.KernelFunctionArgs;
sh = svmStruct.ScaleData.shift; % shift vector
scalef = svmStruct.ScaleData.scaleFactor; % scale vector
group = group(~any(isnan(Xdata),2));
Xdata =Xdata(~any(isnan(Xdata),2),:); % remove rows with NaN
% scale and shift data
Xdata1 = repmat(scalef,size(Xdata,1),1).*(Xdata+repmat(sh,size(Xdata,1),1));
k = 50;
cubeXMin = min(Xdata1(:,1));
cubeYMin = min(Xdata1(:,2));
cubeZMin = min(Xdata1(:,3));
cubeXMax = max(Xdata1(:,1));
cubeYMax = max(Xdata1(:,2));
cubeZMax = max(Xdata1(:,3));
stepx = (cubeXMax-cubeXMin)/(k-1);
stepy = (cubeYMax-cubeYMin)/(k-1);
stepz = (cubeZMax-cubeZMin)/(k-1);
[x, y, z] = meshgrid(cubeXMin:stepx:cubeXMax,cubeYMin:stepy:cubeYMax,cubeZMin:stepz:cubeZMax);
mm = size(x);
x = x(:);
y = y(:);
z = z(:);
f = (feval(kfun,sv,[x y z],kfunargs{:})'*alphaHat(:)) + bias;
t = strcmp(group, group{1});
% unscale and unshift data
Xdata1 =(Xdata1./repmat(scalef,size(Xdata,1),1)) - repmat(sh,size(Xdata,1),1);
x =(x./repmat(scalef(1),size(x,1),1)) - repmat(sh(1),size(x,1),1);
y =(y./repmat(scalef(2),size(y,1),1)) - repmat(sh(2),size(y,1),1);
z =(z./repmat(scalef(3),size(z,1),1)) - repmat(sh(3),size(z,1),1);
figure
plot3(Xdata1(t, 1), Xdata1(t, 2), Xdata1(t, 3), 'b.');
hold on
plot3(Xdata1(~t, 1), Xdata1(~t, 2), Xdata1(~t, 3), 'r.');
hold on
% load unscaled support vectors for plotting
sv = svmStruct.SupportVectorIndices;
sv = [Xdata1(sv, :)];
plot3(sv(:, 1), sv(:, 2), sv(:, 3), 'go');
legend(group{1},group{end},'support vectors')
x0 = reshape(x, mm);
y0 = reshape(y, mm);
z0 = reshape(z, mm);
v0 = reshape(f, mm);
[faces,verts,colors] = isosurface(x0, y0, z0, v0, 0, x0);
patch('Vertices', verts, 'Faces', faces, 'FaceColor','k','edgecolor', 'none', 'FaceAlpha', 0.5);
grid on
box on
view(3)
hold off
end
Example plot:
% load data
load fisheriris;
% train svm using three features for two species
svmStruct = svmtrain(meas(1:100,1:3),species(1:100),'showplot','false','kernel_function','rbf',...
'boxconstraint',1,'kktviolationlevel',0.05,'tolkkt',5e-3);
% run function described above
svm_3d_matlab_vis(svmStruct,meas(1:100,1:3),species(1:100))