Manipulating bar3 x-Axis values results into hollow barplot - matlab

I am setting up a bar3 plot and manipulated the X-Axis values since there is not a better way to do so. I went thorugh the code that Ander Biguri provided in his answer to this thread: How to set x and y values when using bar3 in Matlab?.
It turns out that the X-Axis values are fine but the bars that are not located at the borders are archetype shaped. Probably it has to do with the data manipulation.
Here is the corrisponding plot:
The data i used for this example:
klasse_sig_a=[70 82 94 106 118 130 142 154 166 178 190];
klasse_sig_m=[-120 -102 -84 -66 -48 -30 -12 6 24 42 60];
RFMatrix=
[2 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 0 0;
0 0 0 0 2 0 0 0 0 2;
0 0 0 0 1 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 0 0 2 0 0 0 0 0;]
My code:
b=bar3(klasse_sig_m(2:end),RFMatrix,1);
xlabel('\sigma_a [MPa]')
ylabel('\sigma_m [MPa]')
zlabel('N [-]')
axis tight
for k = 1:length(b)
zdata = b(k).ZData;
b(k).CData = zdata;
b(k).FaceColor = 'interp';
end
Xdat=get(b,'XData');
diff=klasse_sig_a(2)-klasse_sig_a(1);
ONEMAT=ones(size(Xdat{1},1),size(Xdat{1},2)/2);
for ii=1:length(Xdat)
MAT=(Xdat{ii}-0.5);
if ii==1
MAT=MAT+[ONEMAT*min(klasse_sig_a) ONEMAT*(min(klasse_sig_a)+diff)-ii];
MAT_VOR=MAT(:,3:4);
else
MAT(:,1:2)=MAT_VOR;
MAT(:,3:4)=MAT(:,3:4)+ONEMAT*(min(klasse_sig_a)+ii*diff)-ii;
MAT_VOR=MAT(:,3:4);
end
Xdat{ii}=MAT;
set(b(ii),'XData',Xdat{ii});
end
set(gca,'XTick', klasse_sig_a(1:2:end))
set(gca,'YTick', klasse_sig_m(1:2:end))
I noticed that the non manipulated data always has a difference of 1 between left and right side of the matrix for each xdata{ii}
... ... ... ...
NaN NaN NaN NaN
NaN 0.5000 1.5000 NaN
0.5000 0.5000 1.5000 1.5000
0.5000 0.5000 1.5000 1.5000
NaN 0.5000 1.5000 NaN
NaN 0.5000 1.5000 NaN
NaN NaN NaN NaN
When setting my own data the difference becomes much bigger and the bar plots become hollow
... ... ... ...
NaN 70 82 NaN
70 70 82 82
70 70 82 82
NaN 70 82 NaN
NaN 70 82 NaN
NaN NaN NaN NaN
How can I make the bars appear solid again? I guess the data manipulation is erroneous.
Thanks for any help!
Regards

Note that the answer to the related question is specifically designed to deal with the case when your x values are sequential integers (i.e. the bin width is 1). Your case is more general, with a bin width of 12. This requires slightly different logic. I was able to get your desired results with the following code:
b = bar3(klasse_sig_m(2:end), RFMatrix,1);
xlabel('\sigma_a [MPa]');
ylabel('\sigma_m [MPa]');
zlabel('N [-]');
axis tight;
for k = 1:length(b)
xData = b(k).XData;
zData = b(k).ZData;
set(b(k), 'XData', (xData-k).*diff(klasse_sig_a(k:(k+1)))+klasse_sig_a(k), ...
'CData', zData, 'FaceColor', 'interp');
end
set(gca, 'XTick', klasse_sig_a(1:2:end), 'YTick', klasse_sig_m(1:2:end));
And the plot:

Related

How to reorder the rows and columns of a matrix multiplying a vector indexed by (i,j)

I am trying to construct a particular matrix A which multiplies a column vector v= [p_0,0; p_0,1; ... p_0,N; p_1,0; ...; p_N,N].
I know the required matrix (B say) if the vector v was rearranged in the order given by sorting by the second index before the first ( i.e if v were [p_0,0; p_1,0; ... p_N,0; p_0,1; ...; p_N,N]), however would like to rearrange the rows and columns of this matrix to obtain A so that it multiplies the correctly ordered v.
Example:
B =
-2.6667 1.0000 0 0 0 0 0 0 0
-0.5000 0 0.5000 0 0 0 0 0 0
0 -1.0000 -0.4706 0 0 0 0 0 0
0 0 0 -2.6667 1.0000 0 0 0 0
0 0 0 -0.5000 0 0.5000 0 0 0
0 0 0 0 -1.0000 -0.4706 0 0 0
0 0 0 0 0 0 -2.6667 1.0000 0
0 0 0 0 0 0 -0.5000 0 0.5000
0 0 0 0 0 0 0 -1.0000 -0.4706
multiplying v in the wrong order
p_0,0
p_1,0
p_2,0
p_0,1
p_1,1
p_2,1
p_0,2
p_1,2
p_2,2
As long as I understood, you want to convert matrix B to the matrix A in the following order:
v1= [p_0,0; p_0,1; ... p_0,N; p_1,0; ...; p_N,N]
v2=[p_0,0; p_1,0; ... p_N,0; p_0,1; ...; p_N,N]
where A*v1 equals to B*v2.
For this, you need swapping of each row of the matrix.
Try this code:
m=length(B); % m is equal to NxN
N=sqrt(m);
A=zeros(m,m);
for i=0:N-1
for j=0:N-1
A(j+i*N+1,:)=B(i+N*j+1,:);
end
end

DGESV gives wrong solution?

all. I'm trying to solve a Ax=B system in fortran by calling DGESV from lapack.
where,
A =[
1 0 1 0 1 0 1
0 1 0 1 0 1 0
0 0 4 0 32 0 108
0 0 0 24 0 120 0
0 0 0 0 48 0 192
0 0 0 0 0 80 0
0 0 0 0 0 0 120]
B=[
0
0
2
6
0
0
0]
x can be simply calculated in Matlab by x=A\B, which gives
x =
-0.5000
-0.2500
0.5000
0.2500
0
0
0
while I doing the same thing in Fortran, it gives me totally different values. Is there anything wrong with my code or I just make errors in calling DGESV?
Here is my fortran code:
program GG
implicit none
integer, parameter :: N=7
integer :: i,j,ipiv(N),ok
real(8), dimension(1:N,1:N) :: M
real(8), dimension(1,1:N) :: b
M(:,1)=(/1.,0.,1.,0.,1.,0.,1./)*1.d0
M(:,2)=(/0.,1.,0.,1.,0.,1.,0./)*1.d0
M(:,3)=(/0.,0.,2.**3/2,0.,4.**3/2,0.,6.**3/2/)*1.d0
M(:,4)=(/0.,0.,0.,3.*(3.**2-1.),0.,5.*(5.**2-1.),0./)*1.d0
M(:,5)=(/0.,0.,0.,0.,4.*(4.**2-2.**2),0.,6.*(6.**2-2.**2)/)*1.d0
M(:,6)=(/0.,0.,0.,0.,0.,5.*(5.**2-3.**2),0./)*1.d0
M(:,7)=(/0.,0.,0.,0.,0.,0.,6.*(6.**2-4.**2)/)*1.d0
b=reshape((/0,0,2,6,0,0,0/)*1.d0,shape(b))
call DGESV(N,1,M,N,ipiv,b,N,ok)
write(*,*), b
end program GG
the results given by this code is:
0.0000000000000000 0.0000000000000000 0.50000000000000000 0.25000000000000000 -0.33333333333333337 -0.37500000000000000 8.3333333333333315E-002
thanks, sincerely.
The matrix you are creating in Fortran appears to be the transpose (rows and columns flipped) of the one you define in MATLAB. Note (in MATLAB):
>> A = [1 0 1 0 1 0 1
0 1 0 1 0 1 0
0 0 4 0 32 0 108
0 0 0 24 0 120 0
0 0 0 0 48 0 192
0 0 0 0 0 80 0
0 0 0 0 0 0 120];
>> B = [0 0 2 6 0 0 0];
>> x = A\B.'
x =
-0.5000
-0.2500
0.5000
0.2500
0
0
0
>> x = (A.')\B.' % A is transposed, and you get your Fortran result
x =
0
0
0.5000
0.2500
-0.3333
-0.3750
0.0833
In other words, doing M(:,1)=... in Fortran fills the first column, not the first row. If you flip them to M(1,:)=... and so forth, I think it should match the results from MATLAB.

Vectorization using accumarray

I want to project the texture of 3D surface (CylCoors 300000x3) into a 2D plane (Image 380x360). For doing so I take every unique value in Z (UniqueZ=unique(CylCoors(:,3))) and and Theta (UniqueTheta=unique(CylCoors(:,1))) and project all the texture values (PointValues 300000x1) where both meet like this:
Image=zeros(max(UniqueH),max(UniqueTheta)); %380x360
tic
HMat=bsxfun(#eq,CylCoors(:,3),UniqueH'); % 300000x380
ThetaMat=bsxfun(#eq,CylCoors(:,1),UniqueTheta'); %300000x360
for ii=1:length(UniqueH) % Sloooow and not nice :(
for jj=1:length(UniqueTheta)
Image(ii,jj)=sum(PointValues.*...
HMat(:,ii).*ThetaMat(:,jj))/...
sum(HMat(:,ii).*ThetaMat(:,jj));
end
end
toc
Here's an example with trimmed variables:
CylCoorsSample = [263.0000 184.2586 10.0000
264.0000 183.0417 10.0000
264.0000 182.1572 10.0000
82.0000 157.4746 11.0000
80.0000 158.2348 11.0000
86.0000 157.3507 11.0000
84.0000 157.7633 11.0000]
PointValuesSample = [0.4745
0.5098
0.5020
0.4784
0.4510
0.4431
0.5804]
UniqueTheta = [80
82
84
86
263
264]
UniqueH =[10
11]
ThetaMat = HMat =
0 0 0 0 1 0 1 0
0 0 0 0 0 1 1 0
0 0 0 0 0 1 1 0
0 1 0 0 0 0 0 1
1 0 0 0 0 0 0 1
0 0 0 1 0 0 0 1
0 0 1 0 0 0 0 1
Image = % size: length(UniqueH)xlength(UniqueTheta)
NaN NaN NaN NaN 0.4745 0.5059
0.4510 0.4784 0.5804 0.4431 NaN NaN
Is there a way to vectorize the for loops using accumarray? Something tells me this is the case, but I find the multidimensional sub indexing for this function quite confusing.
Any other vectorization solutions (using smart combinations of reshape,bsxfun, and sum I assume) are also welcome, but I would really like to understand this use of accumarray a bit better.
Given:
CylCoorsSample = [263.0000 184.2586 10.0000
264.0000 183.0417 10.0000
264.0000 182.1572 10.0000
82.0000 157.4746 11.0000
80.0000 158.2348 11.0000
86.0000 157.3507 11.0000
84.0000 157.7633 11.0000]
PointValuesSample = [0.4745
0.5098
0.5020
0.4784
0.4510
0.4431
0.5804]
You can use accumarray as follows (using the third output of unique to generate the required subs input):
[UniqueTheta, ~, subsTheta]=unique(CylCoorsSample(:,1))
[UniqueH,~,subsH]=unique(CylCoorsSample(:,3))
sz = [numel(UniqueH), numel(UniqueTheta)]
Image = accumarray([subsH, subsTheta], PointValuesSample, sz, #mean, NaN)

MATLAB, I want to fill a 15 column matrix with a few fixed selected values such that all combinations are covered

Example, I wish to fill a 15 column matrix with the values 0.25,0.25,0.25,0.25,0,0,0 .....( 11 columns with zeros) so that all possible column combinations are filled. In this example I am using 4 columns with 0.25 and the other 11 col's with 0's.
Result should look like :-
0.25 0.25 0.25 0.25 0.00 0.00 0.00 0.00 .......
0.25 0.25 0.25 0.00 0.25 0.00 0.00 0.00 .......
0.25 0.25 0.25 0.00 0.00 0.25 0.00 0.00 .......
. . . . . . . . .......
. . . . . . . . .......
0.25 0.25 0.00 0.25 0.25 0.00 0.00 0.00 .......
0.25 0.25 0.00 0.25 0.00 0.25 0.00 0.00 ....... etc, etc.
When using "perms" (limited to 10 elements anyway ) it treats each "0" as if they are unique hence I get multiple rows that are the same. The "unique" function works fine if less than 10 elements but I need to use more than that. Appreciate any assistance, thanks
The function accumarray is your friend in this case. I'll do a simpler example - creating a six column matrix with exactly two columns filled and the rest zero.
First, we get the list of horizontal indices that you want to be filled using nchoosek
x = nchoosek(1:6, 2);
Now get the vertical coordinates
y = repmat((1:size(x,1))', 1, 2);
Finally, use accumarray to create the desired matrix
z = accummarray([y(:), x(:)], 0.5);
The result is
>> z
z =
0.5000 0.5000 0 0 0 0
0.5000 0 0.5000 0 0 0
0.5000 0 0 0.5000 0 0
0.5000 0 0 0 0.5000 0
0.5000 0 0 0 0 0.5000
0 0.5000 0.5000 0 0 0
0 0.5000 0 0.5000 0 0
0 0.5000 0 0 0.5000 0
0 0.5000 0 0 0 0.5000
0 0 0.5000 0.5000 0 0
0 0 0.5000 0 0.5000 0
0 0 0.5000 0 0 0.5000
0 0 0 0.5000 0.5000 0
0 0 0 0.5000 0 0.5000
0 0 0 0 0.5000 0.5000
Packaging it up as a function, you get
function z = combinations(N, K)
x = nchoosek(N, K);
y = repmat((1:size(x,1))', 1, K);
z = accumarray([y(:), x(:)], 1);
end
you can use combn from the file exchange.
For example:
c = combn([0 0.25],15);
ind = find(sum(c')==1);
Result = c(ind,:)
The tactic here is probably an overkill but it's so simple and easy to implement, I thought to myself, why not?
First, get all possible combinations of 0 and 0.25 for a vector of length 15 (there are 2^15 of those), as done in the first line, where we obtain a [2^15 x 15] matrix (c). Then we find rows in c of that sum up to 1, meaning that the value 0.25 appears exactly four times. Then, use this back in c and VoilĂ !
If you want to obtain c yourself (without combn), this is how to do it:
V = [0 0.25];
a = [0:2^15-1]+(1/2) ;
b = [2.^(1-15:0)] ;
id = rem( floor((a(:) * b(:)')) , 2 ) + 1 ;
c = V(id) ;

Probability of a number occurring in a matrix

I'm using Matlab and well it's straightforward to find the probability of an element in a matrix, but I a little unsure of how to find probability of an element in a row or column.
e.g this matrix:
X = [
1 2 4 1 8;
5 3 6 9 2;
6 2 2 3 2
];
How would I find the probability of "2" occurring in each row and column of this random matrix.
You could do the following:
X_unique = unique(X);
p_row = zeros(size(X,1),numel(X_unique));
p_col = zeros(size(X,2),numel(X_unique));
for ii = 1:size(X,1)
p_row(ii,:) = hist(X(ii,:),X_unique);
p_row(ii,:) = p_row(ii,:)/sum(p_row(ii,:));
end
for ii = 1:size(X,2)
p_col(ii,:) = hist(X(:,ii),X_unique);
p_col(ii,:) = p_col(ii,:)/sum(p_col(ii,:));
end
Now, each row of p_row contains the probability distribution of the elements of unique(X) in the corresponding row of X and each row of p_col contains the probability distribution of the elements of unique(X) in the corresponding column of X.
For example, for the given example,
X_unique =
1
2
3
4
5
6
8
9
Thus,
p_row =
0.4000 0.2000 0 0.2000 0 0 0.2000 0
0 0.2000 0.2000 0 0.2000 0.2000 0 0.2000
0 0.6000 0.2000 0 0 0.2000 0 0
p_col =
0.3333 0 0 0 0.3333 0.3333 0 0
0 0.6667 0.3333 0 0 0 0 0
0 0.3333 0 0.3333 0 0.3333 0 0
0.3333 0 0.3333 0 0 0 0 0.3333
0 0.6667 0 0 0 0 0.3333 0
Here's a simple, not-quite-Matlab-ish solution that works on non-empty bi-dimensional matrices, looking for elements with the value "2", and returning probabilities by column:
a = [1 2 4 1 8; 5 3 6 9 2; 6 2 2 3 2];
nrows = size(a,1);
ncols = size(a,2);
pc = zeros(1, ncols); % Prob. by column
% Iterate trough columns
for k = 1:ncols
n = sum(a(:,k) == 2);
pc(k) = n/nrows;
end;
You can adapt it to compute "probabilities" by row, or by other dimensions, or look for other values.