In my research area (meteorology) graphs within graphs are commonly produced.
more information about it can be found here.
Each of those lines joints up data points that have:
An x-value, between 0 and 1 (values greater than 1 should not be represented in the graph).
A y-value, between 0 and 1.
A PSS value, between 1 and -1.
A Frequency Bias value, ranging from 0 to +∞, but values higher than 4 are not displayed.
A False Alarm Ratio (FAR) value, ranging from 0.0 to 0.9. The False Alarm Ratio value is held constant at a particular value for each data point on any given line.
EDIT: To make things really concrete, I've drawn a pink dot on the graph. That dot represents a data point for which x=0.81, y=0.61, PSS=-0.2, B=3.05, FAR=0.8.
I am trying to reproduce something similar in MATLAB. Googling turned up a lot of answers like this, which feature inset figures rather than what I'm looking for.
I have the data organized in a 3D array, where each page refers to a different level of False Alarm Ratio. The page with a FAR of 0.8 (data here) starts out like this
Then there are other pages on the 3D array devoted to FARs of 0.7, 0.6, and so on.
Questions
1. Is it even possible to create such an graph in MATLAB?
2. If so, what function should I use, and what approach should I take? EDIT: I have working code (below) that creates a somewhat similar figure using the linear plot function, but the documentation for this function does not indicate any way to insert a graph inside another graph. I am not sure how helpful this code is, but have inserted it in response to the downvoter.
H = [0:0.01:1];
figure; hold on
fill([0 1 1],[0 0 1],[0 0.2 0.4]) % Deep blue
fill([0 1 0],[0 1 1],[0.4 0 0]) % Purple
low_colours = {[0 0.501 1],[0 0.8 0.4], [0.4 0.8 0], [0.8 0.8 0]};
high_colours = {[0.6 0 0],[0.8 0 0], [1 0.5019 0], [0.988 0.827 0.196]};
colour_counter = 0;
for ii = -0.8:0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = low_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
colour_counter = 0;
for ii = 0.8:-0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = high_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
I think I got what you want, but before you go to the code below, notice the following:
I didn't need any of your functions in the link (and I have no idea what they do).
I also don't really use the x and y columns in the data, they are redundant coordinates to the PSS and B.
I concat all the 'pages' in your data to one long table (FAR below) with 5 columns (FAR,x,y,PSS,FB).
If you take closer look at the data you see that some areas that supposed to be colored in the graph has no representation in it (i.e. no values). So in order to interpolate the color to there we need to add the corners:
FAR{end+1,:} = [0.8 0 0 0 4];
FAR{end+1,:} = [0.9 0 0 -0.66 3.33];
FAR{end+1,:} = [1 0 0 0 0];
FAR{end+1,:} = [1 0 0 -1 3];
Next, the process has 2 parts. First we make a matrix for each variable, that ordered in columns by the corresponding FAR value, so for instance, in the PSS matrix the first column is all PSS values where FAR is 0, the second column is all PSS values where FAR is 0.1, and so on. We make such matrices for FAR(F), PSS and FreqBias(B), and we initialize them with NaNs so we can have columns with different number of values:
F = nan(max(histcounts(FAR.FAR,10)),10);
PSS = F;
B = F;
c = 1;
f = unique(FAR.FAR).';
for k = f
valid = FAR.FAR==k & FAR.x<=1;
B(1:sum(valid),c) = FAR.FB(valid);
B(sum(valid):end,c) = B(sum(valid),c);
PSS(1:sum(valid),c) = FAR.PSS(valid);
PSS(sum(valid):end,c) = PSS(sum(valid),c);
F(:,c) = k;
c = c+1;
end
Then we set the colors for the colormap (which I partially took from you), and set the labels position:
colors = [0 0.2 0.4
0 0.501 1;
0 0.8 0.4;
0.4 0.8 0;
0.8 0.8 0;
0.988 0.827 0.196;
1 0.5019 0;
0.8 0 0;
0.6 0 0.2;
0.4 0.1 0.5];
label_pos =[0.89 0.77
1.01 0.74
1.14 0.69
1.37 0.64
1.7 0.57
2.03 0.41
2.65 0.18
2.925 -0.195
2.75 -0.55];
And we use contourf to plot everything together, and set all kind of properties to make it look good:
[C,h] = contourf(B,PSS,F);
xlim([0 4])
ylim([-1 1])
colormap(colors)
caxis([0 1])
xlabel('Frequency Bias B')
ylabel('Pierce Skill Score PSS')
title('False Alarm Ratio')
ax = h.Parent;
ax.XTick = 0:4;
ax.YTick = -1:0.5:1;
ax.FontSize = 20;
for k = 1:numel(f)-2
text(label_pos(k,1),label_pos(k,2),num2str(f(k+1)),...
'FontSize',12+k)
end
And here is the result:
Getting the labels position:
If you wonder what is a fast way to obtain the variable label_pos, then here is how I made it...
You run the code above without the last for loop. Then you run the following code:
clabel(C,'manual')
f = gcf;
label_pos = zeros(numel(f.Children.Children)-1,2);
for k = 1:2:size(label_pos,1)
label_pos(k,:) = f.Children.Children(k).Position(1:2);
end
label_pos(2:2:size(label_pos,1),:) = [];
After the first line the script will pause and you will see this message in the command window:
Carefully select contours for labeling.
When done, press RETURN while the Graph window is the active window.
Click on the figure where you want to have a label, and press Enter.
That's it! Now the variable label_pos has the positions of the labels, just as I used it above.
Related
I am novice to deep learning so I begin with the simplest test case: XOR learning.
In the new edition of Digital Image Processing by G & W the authors give an example of XOR learning by a deep net with 3 layers: input, hidden and output (each layer has 2 neurons.), and a sigmoid as the network activation function.
For network initailization they say: "We used alpha = 1.0, an inital set of Gaussian random weights of zero mean and standard deviation of 0.02" (alpha is the gradient descent learning rate).
Training was made with 4 labeled examples:
X = [1 -1 -1 1;1 -1 1 -1];%MATLAB syntax
R = [1 1 0 0;0 0 1 1];%Labels
I have written the following MATLAB code to implement the network learing process:
function output = neuralNet4e(input,specs)
NumPat = size(input.X,2);%Number of patterns
NumLayers = length(specs.W);
for kEpoch = 1:specs.NumEpochs
% forward pass
A = cell(NumLayers,1);%Output of each neuron in each layer
derZ = cell(NumLayers,1);%Activation function derivative on each neuron dot product
A{1} = input.X;
for kLayer = 2:NumLayers
B = repmat(specs.b{kLayer},1,NumPat);
Z = specs.W{kLayer} * A{kLayer - 1} + B;
derZ{kLayer} = specs.activationFuncDerive(Z);
A{kLayer} = specs.activationFunc(Z);
end
% backprop
D = cell(NumLayers,1);
D{NumLayers} = (A{NumLayers} - input.R).* derZ{NumLayers};
for kLayer = (NumLayers-1):-1:2
D{kLayer} = (specs.W{kLayer + 1}' * D{kLayer + 1}).*derZ{kLayer};
end
%Update weights and biases
for kLayer = 2:NumLayers
specs.W{kLayer} = specs.W{kLayer} - specs.alpha * D{kLayer} * A{kLayer - 1}' ;
specs.b{kLayer} = specs.b{kLayer} - specs.alpha * sum(D{kLayer},2);
end
end
output.A = A;
end
Now, when I am using their setup (i.e., weights initalizaion with std = 0.02)
clearvars
s = 0.02;
input.X = [1 -1 -1 1;1 -1 1 -1];
input.R = [1 1 0 0;0 0 1 1];
specs.W = {[];s * randn(2,2);s * randn(2,2)};
specs.b = {[];s * randn(2,1);s * randn(2,1)};
specs.activationFunc = #(x) 1./(1 + exp(-x));
specs.activationFuncDerive = #(x) exp(-x)./(1 + exp(-x)).^2;
specs.NumEpochs = 1e4;
specs.alpha = 1;
output = neuralNet4e(input,specs);
I'm getting (after 10000 epoches) that the final output of the net is
output.A{3} = [0.5 0.5 0.5 0.5;0.5 0.5 0.5 0.5]
but when I changed s = 0.02; to s = 1; I got output.A{3} = [0.989 0.987 0.010 0.010;0.010 0.012 0.0.98 0.98] as it should.
Is it possible to get these results with `s=0.02;' and I am doing something wrong in my code? or is standard deviation of 0.02 is just a typo?
Based on your code, I don't see any errors. In my knowledge, the result that you got,
[0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5]
That is a typical result of overfitting. There are many reasons for this to happen, such as too many epochs, too large learning rate, too small sample data, and others.
On your example, s=0.02 limits the values of randomized weights and biases. Changing that to s=1 makes the randomized values unchanged/unscaled.
To make the s=0.02 one work, you can try minimizing the number of epochs or maybe lowering the alpha.
Hope this helps.
I need to plot horizontal bars using the grouped style such that all the bars belonging to each group have the same color but different from other groups (i.e. all bars of the top group are red, the group below it - green, and so on...).
Also, how can I put the values on the top of each bar horizontally? How can I control the position of such values?
This is my code:
y = [91.9 8.1 94.4 5.6; 84.9 15.1 90.12 9.88; 89.4 10.6 91.2 8.8; 72 28 50.9 49.1];
h = barh(y,'grouped');
job = {'group1','group2 ','group 3','group4'};
legend(job,'location','northeast');
This is my current figure:
Here's a hack:
Plot bar graph for 1 row at a time and fill the space with NaNs while specifying a single color for all rows. Plotting NaNs will plot nothing.
[ry, cy] = size(y); %Number of rows and columns of y
hold on;
for k = 1:ry
tmp = [NaN(k-1,cy); y(k,:); NaN(4-k,cy)]; %Filling with NaNs
h{k} = barh(tmp, 'FaceColor', rand(1,3)); %Plotting bar graph in random color
h{k} = h{k}(1); %Store handle of any of the rows (Required for legend)
end
job = {'group1', 'group2', 'group3', 'group4'}; %Required legend entries
legend([h{:}], job); %Default location is already 'northeast' (so can be skipped)
Output:
This is another type of hack; tested on R2017b.
The reason why what you're asking is difficult to do is because each group in a bar plot is actually a Quadrilateral object (i.e. polygon). For example, let's take the 1st Bar object:
>> h(1).Face.VertexData
ans =
3×16 single matrix
Columns 1 through 9
0 91.9000 91.9000 0 0 84.9000 84.9000 0 0
0.6545 0.6545 0.8000 0.8000 1.6545 1.6545 1.8000 1.8000 2.6545
0 0 0 0 0 0 0 0 0
Columns 10 through 16
89.4000 89.4000 0 0 72.0000 72.0000 0
2.6545 2.8000 2.8000 3.6545 3.6545 3.8000 3.8000
0 0 0 0 0 0 0
And if we add this line to the code:
drawnow; hold on; scatter(h(1).Face.VertexData(1,:), h(1).Face.VertexData(2,:));
we get (notice the green circles):
What's interesting is that the points in VertexData are not read-only, which means we can just intelligently "rearrange" the VertexData matrices of the N bar groups to get the desired result. Here's one way to do it (notice I renamed h to hBar):
% Obtain the old VertexData:
vd_old = cell2mat(reshape(get([hBar.Face],'VertexData'),1,1,[]));
% Rearrange VertexData:
nB = numel(hBar);
vd_new = cell2mat(permute(mat2cell(vd_old,3,repelem(4,nB),repelem(1,nB)),[1,3,2]));
% Assign the new VertexData back into the Bar objects' Edge and Face fields:
for indB = 1:nB
hBar(indB).Edge.VertexData = vd_new(:,:,indB);
hBar(indB).Face.VertexData = vd_new(:,:,indB);
end
Finally, we manually add labels using the text command:
xOffset = 1;
for indB = 1:nB
text(double(vd_new(1,2:4:end,indB)) + xOffset, double(tmpY(2:4:end)), ...
string(vd_new(1,2:4:end,indB)),'VerticalAlignment','middle');
end
The end result:
The final code:
function q47978293
close all force;
y = [91.9 8.1 94.4 5.6; 84.9 15.1 90.12 9.88; 89.4 10.6 91.2 8.8; 72 28 50.9 49.1];
figure(47978293); set(gcf,'Position',[786,556,887,420]); hBar = barh(y,'grouped');
legend("group" + (1:4),'location','northeast');
drawnow;
% hold on; scatter(h(1).Face.VertexData(1,:), h(1).Face.VertexData(2,:));
% Obtain the old VertexData:
vd_old = cell2mat(reshape(get([hBar.Face],'VertexData'),1,1,[]));
% Rearrange VertexData:
nB = numel(hBar);
vd_new = cell2mat(permute(mat2cell(vd_old,3,repelem(4,nB),repelem(1,nB)),[1,3,2]));
% Assign the new VertexData back into the Bar objects' Edge and Face fields:
xOffset = 1; % < Adjust as you see fit
for indB = 1:nB
hBar(indB).Edge.VertexData = vd_new(:,:,indB);
hBar(indB).Face.VertexData = vd_new(:,:,indB);
try
text( y(indB,:) + xOffset, mean(reshape(vd_new(2,1:2:end,indB),2,[]),1,'double'), ...
string(vd_new(1,2:4:end,indB)),'VerticalAlignment','middle');
catch % Compatibility fix for R2016b & R2017a. Credit #SardarUsama
text( y(indB,:) + xOffset, mean(reshape(vd_new(2,1:2:end,indB),2,[]),1,'double'), ...
split(num2str(vd_new(1,2:4:end,indB))),'VerticalAlignment','middle');
end
end
end
Note: due to the hacky nature of this solution, if the figure is redrawn (due to e.g. resizing), the bar colors will return to their original state - so make sure that the part that changes colors is the very last thing you do.
P.S.
The R2017b release notes state that this customization should be officially supported now (through the CData property of Bar objects), but I couldn't get the legend to display the correct colors. If you want to try it, just plot using the following command (R2017b+):
barh(y,'grouped','FaceColor','flat','CData',lines(size(y,1)));
The two requests overlap making everything kinda complex, since using uniform colors for each group implies using a workaround that needs another workaround to male bar text work. Here is the code:
y = [
91.90 8.10 94.40 5.60;
84.90 15.10 90.12 9.88;
89.40 10.60 91.20 8.80;
72.00 28.00 50.90 49.10
];
[rows,cols] = size(y);
n = NaN(rows,cols);
c = {'r' 'g' 'b' 'y'};
bh = cell(rows,1);
lh = cell(rows,1);
hold on;
for k = 1:rows
curr = n;
curr(k,:) = y(k,:);
bar = barh(curr,'FaceColor',c{k});
bh{k} = bar;
lh{k} = bar(1);
end
hold off;
legend([lh{:}],{'G1','G2','G3','G4'},'Location','southoutside');
yl = get(gca,'XLim');
yl_up = yl(2);
xoff = yl_up * 0.01;
set(gca,'XLim',[yl(1) (yl_up + (yl_up * 0.1))]);
set(gcf,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
for i = 1:numel(bh)
bh_i = bh{i};
for j = 1:numel(bh_i)
bh_ij = bh_i(j);
hx = bh_ij.YData + xoff;
hy = bh_ij.XData + bh_ij.XOffset;
text(hx,hy,num2str(hx.','%.2f'), ...
'FontSize',10, ...
'HorizontalAlignment','left', ...
'VerticalAlignment','middle');
end
end
And here is the output:
I am writing a code to produce a house with a given height, width, length, and angle of sloped roof.
I was able to produce the walls with surf by using a zero value for a specific dimension, allowing a wall to be made as an x-y plane, x-z plane, etc.
However, Now I am trying to produce a desk inside that is an x-y plane with a specific height, and cant figure out how..
MATLAB says it needs a matrix, but a matrix formed only from the height doesn't work, also using ndgrid(heightValue:.5:heightValue) doesn't work
If anyone knows how to help, I would greatly appreciate it.
Code:
(one of the desk sides is in the wrong place as well for similar problems, but help with this problem will allow me to figure out how to fix it)
clear; clc; close all;
%% INPUT VARIABLES
lengthdlg = 'Please enter length of base (m): ';
widthdlg = 'Please enter width of base (m): ';
heightdlg = 'Please enter height of wall (m): ';
angledlg = 'Please enter the angle of the roof (degrees): ';
dlgbox = inputdlg({lengthdlg, widthdlg, heightdlg, angledlg},...
'Simple AutoCAD', [1 50; 1 50; 1 50; 1 50], {'30','40','15','30'});
BaseL = str2double(dlgbox(1));
BaseW = str2double(dlgbox(2));
WallH = str2double(dlgbox(3));
RoofA = str2double(dlgbox(4));
m = tand(RoofA);
h = figure;
set(h,'name','Simple AutoCAD House','numbertitle','off')
xlabel('x'),ylabel('y'),zlabel('z')
title('Simple AutoCAD House')
colormap white
%% Base/Floor
[xB,yB] = ndgrid(0:1:BaseL, 0:1:BaseW);
zB = (xB*0);
surf(xB,yB,zB,'FaceColor','k')
hold on
%% Walls
%Front Wall (w/Door opening)
[xFW,zFW] = ndgrid(0:1:BaseL, 0:1:WallH);
yFW = (xFW*0);
yFW(xFW>.4*BaseL & xFW<.6*BaseL & zFW<.8*WallH) = nan;
surf(xFW,yFW,zFW);
hold on
%Back Wall
[xBW,zBW] = ndgrid(0:.5:BaseL, 0:.5:WallH);
yBW = (xBW*0)+BaseW;
surf(xBW,yBW,zBW);
%Right Wall
[yRW,zRW] = ndgrid(0:.5:BaseW, 0:.5:WallH);
xRW = (yRW*0)+BaseL;
surf(xRW,yRW,zRW);
%Left Wall
[yLW,zLW] = ndgrid(0:.5:BaseW, 0:.5:WallH);
xLW = (yLW*0);
xLW(yLW>.25*BaseW & yLW<.75*BaseW & zLW>.5*WallH & zLW<.7*WallH) = nan;
surf(xLW,yLW,zLW);
%% Roof
%Left Panel
[xLP,yLP] = ndgrid(0:.5:(BaseL/2), 0:.5:BaseW);
zLP = (m*xLP)+WallH;
surf(xLP,yLP,zLP)
hold on
%Right Panel
[xRP,yRP] = ndgrid((BaseL/2):.5:BaseL, 0:.5:BaseW);
zRP = (-m*xRP)+(WallH+m*BaseL);
surf(xRP,yRP,zRP)
%% Roof Triangles
%Front Triangle
[xFT,zFT] = ndgrid(0:.25:BaseL, WallH:.25:(m*BaseL/2)+WallH);
yFT = 0*xFT;
yFT(zFT>(m*xFT+WallH)) = nan;
yFT(zFT>(-m*xFT+(m*BaseL+WallH))) = nan;
surf(xFT,yFT,zFT)
%Back Triangle
[xBT,zBT] = ndgrid(0:.25:BaseL, WallH:.25:(m*BaseL/2)+WallH);
yBT = (xBT*0)+BaseW;
yBT(zBT>(m*xBT+WallH)) = nan;
yBT(zBT>(-m*xBT+(m*BaseL+WallH))) = nan;
surf(xBT,yBT,zBT)
%% Door
[xD,zD] = ndgrid(.4*BaseL:.5:.6*BaseL, 0:.5:.8*WallH);
yD = xD*0;
door = surf(xD,yD,zD,'FaceColor','g');
%% Windows
%Left Window
[yLWin,zLWin] = ndgrid(.25*BaseW:.5:.75*BaseW, .5*WallH:.5:.75*WallH);
xLWin = (yLWin*0);
surf(xLWin,yLWin,zLWin,'FaceAlpha',.25,'FaceColor','b')
%% Desk and chair
%desktop
[xDT,yDT] = ndgrid(.8*BaseL:.5:.99*BaseL, .7*BaseW:.5:.99*BaseW);
zDT = (0*xDT);
surf(xDT,yDT,zDT,'FaceColor','r')
%DeskNear
[xDN,zDN] = ndgrid(.8*BaseL:.5:BaseL, 0:.5:.25*WallH);
yDN=(0*zDN)
surf(xDN,yDN,zDN,'FaceColor','r')
%% Door Opening
k = waitforbuttonpress;
if k == 0
delete(door)
end
The ZData property of a surface, is the z coordinate for each point in the surface. In your example, you set it to the right size by making it the same size as your XData and YData; however, the way you construct your ZData is a little off. You essentially do this:
zDT = (0 * xDT);
What this effectively does, is forces the z coordinate of every point in the mesh to be 0 (i.e. on the floor). This is why the desk top simply sits on the floor, and also why the side of the desk sits on the side of the wall (y = 0).
To fix this, you want to instead calculate what the values should actually be rather than setting them to zero.
Desktop
The nice thing is that the z value for the entire desktop is actually a constant for the whole surface since it's parallel to the floor. You define what the height of the desktop is when you create the side of the desk.
[xDN, zDN] = ndgrid(.8*BaseL:.5:BaseL, 0:.5:.25*WallH);
Here you're saying the height of the desk is 0.25 * WallH rounded to the previous 0.5 (because of your step size). So we want to set the ZData of the desktop to be that value (the max of zDN) and we can multiply that value by a matrix of ones the size of the XData to make it the right size.
zDT = max(zDN(:)) * ones(size(xDT));
Side of Desk
For the side of the desk, the issue isn't the ZData anymore, it's now the YData. As it currently is, you have it set to all zeros so it get's stuck to the wall at y = 0.
yDN = (0 * zDN);
Again, we want the y value to be constant for the whole side of the desk. We can compute what this y value is by using the minimum y value from the desk top (again, making sure it's the right size by using a matrix of ones).
yDN = min(yDT(:)) * ones(size(xDN));
Summary
We can make those two changes and this makes the bottom portion of your code look something like this.
%desktop
[xDT,yDT] = ndgrid(.8*BaseL:.5:.99*BaseL, .7*BaseW:.5:.99*BaseW);
[xDN,zDN] = ndgrid(.8*BaseL:.5:BaseL, 0:.5:.25*WallH);
zDT = max(zDN(:)) * ones(size(xDT));
surf(xDT,yDT,zDT,'FaceColor','r')
%DeskNear
yDN = min(yDT(:)) * ones(size(xDN));
surf(xDN,yDN,zDN,'FaceColor','r')
If we apply that, we get the desktop off of the floor and the side of the desk where it belongs.
As Amro said in the comment to your post, it will likely be much easier to draw this sort of thing using patch rather than surf as it gives you a great deal more flexibility as far as shapes.
Here is my version of the house :)
Code should be easy to follow. Note that I'm using the patch function instead.
% input measurements
BaseL = 30;
BaseW = 40;
WallH = 15;
RoofA = 30;
% colors
m = tand(RoofA);
clr = hsv(10);
clf
% floor
patch([0 1 1 0].*BaseL, ...
[0 0 1 1].*BaseW, ...
[0 0 0 0].*WallH, clr(1,:));
% front wall (w/ door opening)
patch([1 1 0 0 0.4 0.4 0.6 0.6].*BaseL, ...
[0 0 0 0 0 0 0 0].*BaseW, ...
[0 1 1 0 0 0.8 0.8 0].*WallH, clr(2,:));
% back wall
patch([0 1 1 0].*BaseL, ...
[1 1 1 1].*BaseW, ...
[0 0 1 1].*WallH, clr(3,:));
% right wall
patch([1 1 1 1].*BaseL, ...
[0 0 1 1].*BaseW, ...
[0 1 1 0].*WallH, clr(4,:));
% left wall (w/ window opening)
patch([0 0 0 0 0 0 0 0 0 0 0 0].*BaseL, ...
[0 0 0.5 0.5 0.25 0.25 0.75 0.75 0.5 0.5 1 1].*BaseW, ...
[0 1 1 0.7 0.7 0.5 0.5 0.7 0.7 1 1 0].*WallH, clr(5,:));
% roof left/right panels
patch([0 0.5 0.5 0].*BaseL, ...
[0 0 1 1].*BaseW, ...
[0 1 1 0].*(m*BaseL/2)+WallH, clr(6,:));
patch([1 0.5 0.5 1].*BaseL, ...
[0 0 1 1].*BaseW, ...
[0 1 1 0].*(m*BaseL/2)+WallH, clr(7,:));
% roof front/back triangles
patch([0 1 0.5].*BaseL, ...
[0 0 0].*BaseW, ...
[0 0 1].*(m*BaseL/2)+WallH, clr(8,:));
patch([0 1 0.5].*BaseL, ...
[1 1 1].*BaseW, ...
[0 0 1].*(m*BaseL/2)+WallH, clr(9,:));
% door
hDoor = patch([0.4 0.6 0.6 0.4].*BaseL, ...
[0 0 0 0].*BaseW, ...
[0 0 0.8 0.8].*WallH, 'k', 'FaceAlpha',0.75);
% window on left wall
hWin = patch([0 0 0 0].*BaseL, ...
[0.25 0.75 0.75 0.25].*BaseW, ...
[0.5 0.5 0.7 0.7].*WallH, 'k', 'FaceAlpha',0.75);
% table inside
patch([0.8 0.99 0.99 0.8].*BaseL, ...
[0.7 0.7 0.99 0.99].*BaseW, ...
[0.2 0.2 0.2 0.2].*WallH, clr(10,:));
patch([0.8 0.99 0.99 0.8].*BaseL, ...
[0.7 0.7 0.7 0.7].*BaseW, ...
[0.01 0.01 0.2 0.2].*WallH, clr(10,:));
patch([0.8 0.99 0.99 0.8].*BaseL, ...
[0.99 0.99 0.99 0.99].*BaseW, ...
[0.01 0.01 0.2 0.2].*WallH, clr(10,:));
% 3D view
axis([0 BaseL 0 BaseW 0 WallH*2]), axis vis3d
view(3), grid on
xlabel('X'), ylabel('Y'), zlabel('Z')
title('Simple AutoCAD House')
% animate door/window transparencies
t = linspace(-pi,pi,20);
anim = #(t) 1-(tanh(t)+1)/2; % smooth function from 1 to 0
for i=1:numel(t)
set([hDoor,hWin], 'FaceAlpha',anim(t(i)))
pause(0.1)
end
There is a small animation at the end, where the door and window go from tinted to clear. Hope you like it!
I have the following code:
limits = [-1 1 -1 1];
g1 = [1;2;3;4;5;6;7;8];
col = [1 1 0; 1 0 1; 0 1 1; 1 0 0; 0 1 0; 0 0 1; 0 0 0; 0.5 0.3 0.1];
sym = 'vvvv^^^^';
sym2 = 'xxxxxxxx';
points = 30;
for i = 1:8;
mhuR(i,1) = mean(HSRXdistpR(i,:));
mhuR(i,2) = mean(HSRYdistpR(i,:));
mhuL(i,1) = mean(HSRXdistpL(i,:));
mhuL(i,2) = mean(HSRYdistpL(i,:));
mhuX(i,1) = mean(TotxcomHSRpX(i,:));
mhuX(i,2) = mean(TotxcomHSRpY(i,:));
CR{i} = cov(HSRXdistpR(i,:),HSRYdistpR(i,:));
CL{i} = cov(HSRXdistpL(i,:),HSRYdistpL(i,:));
CX{i} = cov(TocomXdistp(i,:),TocomYdistp(i,:));
ellipR{i} = uncertEllip(CR{i},mhuR(i,:),points);
ellipL{i} = uncertEllip(CL{i},mhuL(i,:),points);
ellipX{i} = uncertEllip(CX{i},mhuX(i,:),points);
end
figure; hold on
scatter(HSRXdistbR2,HSRYdistbR2,'ko'); hold on
scatter(HSRXdistbL2,HSRYdistbL2,'ko'); hold on
scatter(TocomXdistb2,TocomYdistb2,'kx'); hold on
gscatter(HSRXp2(:,1),HSRYp2(:,1),g1,col,sym), hold on
gscatter(HSRXp2(:,2),HSRYp2(:,2),g1,col,sym), hold on
gscatter(copHSRXp2(:,2),copHSRYp2(:,2),g1,col,sym2), hold on
for i = 1:8;
plot(ellipR{i}(:,1),ellipR{i}(:,2),col(i,:)), hold on
plot(ellipL{i}(:,1),ellipL{i}(:,2),col(i,:)), hold on
plot(ellipX{i}(:,1),ellipX{i}(:,2),col(i,:)), hold on
end
vline(0)
hline(0)
legend('base','base','base','-0.04m', '-0.08m', '-0.12m', '-0.16m', '0.04m', '0.08m', '0.12m', '0.16m');
title({'xCoM and left and right foot placement relative',...
'to xCoM per perturbation, for all subjects'})
axis(limits)
xlabel('x displacement (scaled)');
ylabel('y displacement (scaled)');`
I'm trying to get the line plots (second for loop) to have the same colors as the scatter plot data (the uncertainty ellipses each belong to their own scatter point). However, it won't allow me to use the colors from the col matrix. Am I missing something here?
Error:
Data must be a single matrix Y or a list of pairs X,Y.
Not trying to define the colors works fine, but of course the colors don't match.
Try replacing each of those erroring lines with this:
plot(ellipR{i}(:,1),ellipR{i}(:,2),'Color',col(i,:));
i run below code, but get X, Y, Z, and C cannot be complex error, any idea what is wrong?
k=1;
u = linspace(0,2*pi,72);
v = [-3:.2:-1,1:.2:3];
[U,V] = meshgrid(u,v);
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
X = r.*cos(U);
Y = r.*sin(U);
Z = V;
This is the image I want to get:
http://adasu.info/plates.png
The full code is:
function simple_math_functions_animation1
clc, close all, clear all
hf1=figure(1);hold on,grid on,axis equal, view([1 -1 1])
set(hf1,'Color','w');set(hf1,'Position',[300, 600, 500, 400]);
xlabel('x');ylabel('y'),zlabel('z');
k=1;
u = linspace(0,2*pi,72);
v = [-3:.2:-1,1:.2:3];
[U,V] = meshgrid(u,v);
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
X = r.*cos(U);
Y = r.*sin(U);
Z = V;
surf(X,Y,Z,'EdgeColor',[0.5 1. 0.2],'FaceColor',[1 0.2 0.8],'FaceAlpha',0.6);
XYZ=[reshape(X,1,prod(size(X)));
reshape(Y,1,prod(size(Y)));
reshape(Z,1,prod(size(Z)));
ones(1,prod(size(Z)))];
phi=[0 : pi/20 : 50*pi];
h=[]; axis([-20 20 -20 20 -20 20]);
for beta=phi % animation loop *****************
T=[cos(beta) -sin(beta) 0 0; % rotation matrix
sin(beta) cos(beta) 0 0;
0 0 1 0;
0 0 0 1];
XYZ1=T*XYZ; % coordinates changing
X1=reshape(XYZ1(1,:),size(X));Y1=reshape(XYZ1(2,:),size(Y));Z1=reshape(XYZ1(3,:),size(Z));
pause(0.1);if ~isempty(h),delete(h);end
h=surf(X1,Y1,Z1,'EdgeColor',[0.5 1. 0.2],'FaceColor',[0.2 0.2 0.8],'FaceAlpha',0.6);
end % ******************************************
end
You are getting that complex error because r is complex-valued. r is used in both X and Y and so when it's time to use surf on these inputs, you finally get that error. That makes sense because your range of V has negative values, and when you set k=1 for this expression:
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
You are effectively trying to take the square root of values in V and some of them are negative, and hence r is complex valued. If you look at your actual image you uploaded, you are missing a 2 in the power of V. Therefore:
r=sqrt((4*V.^2-k)./(cos(U).^2+k*sin(U).^2));
When I do this, then try running your code, I get this: