simplify coordinate calculation - algorithm

I've got an array of N elements.
Need to place them on the screen like a set of groups, where each group is a 4x4 table of elements. Width of a table is TW = 320px. Height is TH = 480px.
In local coordinates of each table:
the gap between columns must be equal; the gap between first column and left border must be equal with the gap between 4th column and right border and must be equal bordersGapX = 60px.
the gap between rows must be equal rowsGapY = 60px; firs row is starting at firstRowY 150px.
In global coordinates of the screen:
tables must be placed one near another with the gap of tablesGapX = 300 px;
Hope related picture helps...
Now we need to set X and Y position for each element in the loop just with the equation - no if operators or inner loops...
I really don't remember how, but I ended up with something like this, and it works:
for i=1,N do
element.x, element.y =
(((i%4)==0) and (TW-borderGapX) or ((i%4==1) and borderGapX or borderGapX+((TW-borderGapX*2)/3)*((i%4)-1) ))+math.floor(i/16)*tablesGapX - ((((i%4==0) and (i%16==0))) and tablesGapX or 0),
firstRowY+math.floor((i-1)/4)*rowsGapY - (math.floor(i/16)*rowsGapY*4) + ((((i%4==0) and (i%16==0))) and rowsGapY*4 or 0)
end
Somebody please help me simplify that!!!

Simplifying readability can be done as follows. You start be defining which table-number and which position-number each element has:
element.tableid = math.floor(i/16)
element.position = i - element.tableid
And then you use helping functions
for i=1,N do
element.tableid = math.floor(i/16)
element.position = i - element.tableid
element.x = compute_offsetxoftable(element.tableid)
element.y = compute_offsetyoftable(element.tableid)
element.x = element.x + compute_offsetxwithintable(element.position)
element.y = element.y + compute_offsetywithintable(element.position)
end
The functions I just implicitly define could even be a mapping table...

Related

Grouping data using loops (signal processing in MATLAB)

I am working in MATLAB with a signal data that consist of consecutive dips as shown below. I am trying to write a code which sorts the contents of each dip into a separate group. How should the general structure of such a code look like?
The following is my data. I am only interested in the portion of the signal that lies below a certain threshold d (the red line):
And here is the desired grouping:
Here is an unsuccessful attempt:
k=0; % Group number
for i = 1 : length(signal)
if signal(i) < d
k=k+1;
while signal(i) < d
NewSignal(i, k) = signal(i);
i = i + 1;
end
end
end
The code above generated 310 groups instead of the desired 12 groups.
Any explanation would be greatly appreciated.
Taking Benl generated data you can do the following:
%generate data
x=1:1000;
y=sin(x/20);
for ii=1:9
y=y+-10*exp(-(x-ii*100).^2./10);
end
y=awgn(y,4);
%set threshold
t=-4;
%threshold data
Y = char(double(y<t) + '0'); %// convert to string of zeros and ones
%search for start and ends
This idea is taken from here
[s, e] = regexp(Y, '1+', 'start', 'end');
%and now plot and see that each pair of starts and end
% represents a group
plot(x,y)
hold on
for k=1:numel(s)
line(s(k)*ones(2,1),ylim,'Color','k','LineStyle','--')
line(e(k)*ones(2,1),ylim,'Color','k','LineStyle','-')
end
hold off
legend('Data','Starts','Ends')
Comments: First of all I choose an arbitrary threshold, it is up to you to find the "best" one in your data. Additionally I didn't group the data explicitly but rather this approach gives you the start and end of each epoch with a dip (you might call it group). So you could say that each index is the grouping index. Finally I did not debug this approach for corner cases, when dips fall on starts and ends...
In MATLAB you cannot change the loop index of a for loop. A for loop:
for i = array
loops over each column of array in turn. In your code, 1 : length(signal) is an array, each of its elements is visited in turn. Inside this loop there is a while loop that increments i. However, when this while loop ends and the next iteration of the for loop runs, i is reset to the next item in the array.
This code therefore needs two while loops:
i = 1; % Index
k = 0; % Group number
while i <= numel(signal)
if signal(i) < d
k = k + 1;
while signal(i) < d
NewSignal(i,k) = signal(i);
i = i + 1;
end
end
i = i + 1;
end
Easy, the function you're looking for is bwlabel, which when combined with logical indexing makes this simple.
To start I made some fake data which resembled your data
x=1:1000;
y=sin(x/20);
for ii=1:9
y=y+-10*exp(-(x-ii*100).^2./10);
end
y=awgn(y,4);
plot(x,y)
Then set your threshold and use 'bwlabel'
d=-4;% set the threshold
groupid=bwlabel(y<d);
bwlabel labels connected groups in a black and white image, what we've effectively done here is make a black and white (logical 0 & 1) 1D image in the logical vector y<d. bwlabel returns the number of the region at the index of the region. We're not interested in the 0 region, so to get the x values or y values of the nth region, simply use x(groupid==n), for example with my test data
x_4=x(groupid==4)
y_4=y(groupid==4)
x_4 = 398 399 400 401 402
y_4 = -5.5601 -7.8280 -9.1965 -7.9083 -5.8751

Algorithm to get cell row and column in table

I am building a function which will allow the user to choose a cell in a dynamically created table, by passing in an integer.
I.e., if I have a 3x3 grid, and the user passes in the number 4, the program should know that he wants the 1st cell in the second row. (the cells will be counted by rows)
As I mentioned, the table is created dynamically and can be any size.
I can do this with a bunch of if statements, but I was wondering if there is maybe an algorithm to figure this out easily.
(P.S. I am using a very basic programming language, so please, no fancy pythonic math functions... :) )
All you need to do is divide by columns and find the remainder. Something like this:
input = 4
row = floor(input / columns)
column = input % columns
Assuming the output should be 1 based index
input = n, k // n * n grid, k number
row = floor( (k - 1) / n ) + 1;
col = k % n;
if(col == 0) {
col += n;
}
// print row, col

Creating fractal image in a plot MATLAB but the plot is empty

I am writing a function to create a fractal image in a plot. When I run my code, a plot pops up but it is empty. I think the issues lies somewhere in my if/elseif statements, but I am having a hard time finding it. My code is:
function [] = fractal(x, y, N)
close all
start = [x, y];
X = zeros(N+1,1);
Y = zeros(N+1,1);
X = start;
hold on
for i = 1:N
prob = rand;
if prob >= 0.01
X(i+1,:) = 0;
Y(i+1,:) = 0.16*y(1);
elseif prob == 0.02:0.86
X(i+1,:) = (0.85*x(i))-(0.04*y(i));
Y(i+1,:) = (-0.04*x(i))+(0.85*y(i))+1.6;
elseif prob == 0.87:0.94
X(i+1,:) = (0.2*x(i))-(0.26*y(i));
Y(i+1,:) = (0.23*x(i))+(0.22*y(i))+1.6;
elseif prob == 0.95:1.0
X(i+1,:) = (-0.15*x(i))+(0.28*y(i));
Y(i+1,:) = (0.26*x(i))+(0.24*y(i))+0.44;
plot(X(i,:),Y(i,:),'.','Markersize',1)
axis equal
end
end
end
When I run my code with
>> fractal(1,1,1000)
... a plot comes up but it is empty.
Yup... it's your if statements, but there are more issues with your code though but we will tackle those later. Let's first address your if statements. If you want to compare in a range of values for examples, you need use the AND (&&) statement. In addition, you should place your plot code outside of any if/elseif/else statement. You currently have it inside your last elseif statement so plot will only run if the last condition is satisfied.
To be explicit, if you wish to compare if a value is in between a certain range, do something like:
if (prob >= a && prob < b)
and for elseif:
elseif (prob >= a && prob < b)
a and b are the lower and upper limits of what you want to compare. This includes a but excludes b in the comparison.
I also have a several comments and recommendations with your current code in order to get this to work:
You run your function with a single x and y value, but you are trying to access this x and y in your for loop as if these were arrays. I'm assuming this is recursive in nature so you need to actually use X and Y in your if/else conditions instead of x and y.
Since you are using single values, it is superfluous to use : to access the second dimension. Just leave that out.
You create X and Y but then overwrite X to be the starting location as a 2D array... I think you meant to replace X and Y's first element with the starting location instead.
Your first if statement I think is incorrect. You'd want to access Y(i) not Y(1) no?... given the behaviour of your code thus far.
Your first condition will definitely mess things up for you. This is saying that as long as the value is greater than or equal to 0.01, execute that statement. Otherwise, try and execute the other conditions which may in fact never work because you are looking for values that are greater than 0.01 where the first condition already handles that for you. I assume you meant to check if it was less than 0.01 instead.
Doing value comparecondition array in MATLAB means that this statement is true provided that any one of the values in array matches the condition provided by value. This will have unintended side effects with your current code.
Make sure that your ranges covered for each if statement are continuous (i.e. no gaps or disconnects between ranges). Right now, you are checking for values in 0.01 intervals. rand generates random values between 0 and 1 exclusive. What if you had a value of 0.15? None of your if conditions handle this so you need to use what I talked about above.
You are most likely getting a blank plot because your MarkerSize attribute is very small.... you set it to 1 pixel. Unless you have super human vision, you can't really visualize this. Make the MarkerSize larger.
Use drawnow; after you plot to immediately update the results to screen.
Therefore, with refactoring your code, you should make it look something like this:
function [] = fractal(x, y, N)
close all
start = [x, y];
X = zeros(N+1,1);
Y = zeros(N+1,1);
%// Change - Initialize first elements of X and Y to be the starting positions
X(1) = start(1);
Y(1) = start(2);
hold on
for i = 1:N
prob = rand;
if prob <= 0.01 %// Change
X(i+1) = 0;
Y(i+1) = 0.16*Y(i); %// Change
elseif (prob > 0.01 && prob <= 0.86) %// Change
X(i+1) = (0.85*X(i))-(0.04*Y(i)); %// Change
Y(i+1) = (-0.04*X(i))+(0.85*Y(i))+1.6; %// Change
elseif (prob > 0.86 && prob <= 0.94) %// Change
X(i+1) = (0.2*X(i))-(0.26*Y(i)); %// Change
Y(i+1) = (0.23*X(i))+(0.22*Y(i))+1.6; %// Change
elseif (prob > 0.94 && prob <= 1.0) %// Change
X(i+1) = (-0.15*X(i))+(0.28*Y(i)); %// Change
Y(i+1) = (0.26*X(i))+(0.24*Y(i))+0.44; %// Change
end
%// Change - move outside of if/else blocks
%// Also make marker size larger
plot(X(i),Y(i),'.','Markersize',18); %// Change
axis equal
%// Add just for kicks
drawnow;
end
end
I now get this figure when I do fractal(1,1,1000):
.... cool fractal btw!

optimizing dynamic programming in matlab

I have a problem with a dynamic programming solution which I'm trying to implement in matlab and was trying to see if there's a better (run-time-wise) implementation than the one I could come up with.
The problem (all values are in the real):
input: let X be a T-by-d matrix, W be a k-by-d matrix and A by a k-by-k matrix.
output: Y T-by-1 array s.t for row i in X Y(i) is the number of a row in W which maximizes our goal.
A(i,j) gives us the cost of choosing row j if the previous row we chose was i.
To calculate the weight of the output, for each row i in X we sum the dot-product of the Y(i) row of W and add the relevant cost from A.
Our goal is to maximaize the said weight.
Dynamic solution:
instantiate a k-by-T matrix
Fill the first column of the matrix with the results of dot-producting the first row of X with each row of W
for each of the same columns (denote as i) fill with the dot-producting of the i row of X with each row of W and add the cost of A(j,i) where j is the row index of the cell in previous column with maximum value
backtrack from the last column, each time choosing the row index of the cell with the highest value
Matlab implementation (with instantiation of variables):
T = 8;
d = 10;
k = 20;
X = rand(T,d);
W = rand(k,d);
A = rand(k);
Y = zeros(T,1);
weight_table = zeros(k,T);
weight_table(:,1) = W*X(1,:)';
for t = 2 : T
[~, prev_ind] = max(weight_table(:,t-1));
weight_table(:,t) = W*X(t,:)' + A(:,prev_ind);
end
[~, Y] = max(weight_table);
Since there is data dependency across iterations, I would advise keeping the loop, but pre-calculate few things like the product of W and transpose of each row of X. This is done here (showing just the weight_table calculation part as the rest of the code stays the same as in the original post) -
weight_table = zeros(k,T);
weight_table(:,1) = W*X(1,:)';
WXt = W*X.'; %//' Pre-calculate
for t = 2 : T
[~, prev_ind] = max(weight_table(:,t-1));
weight_table(:,t) = WXt(:,t) + A(:,prev_ind); %// Use pre-calculated values and thus avoid that multiplication across each iteration
end
For bigger inputs like - T = 800; d = 1000; k = 2000;, I am getting 8-10x performance improvement with it on my system.

Partition an image into 8 rows via Matlab, not all partitions shown

I wish to ask if anybody out there knows how to partition an image into 8 different rows and 1 column? I have tried using mat2cell() and using the demo on their wiki as a reference, I tried partitioning the image into 8 rows, however not all image partition rows are displayed.
If you see the image below, 2, 4, 6, 8 is not displayed. I am also not sure why is it of 16 blocks.
Can somebody help me check my code? I am not really used to the MatLab syntax and language. I trying my best to understand now.
My code for splitting the blocks are as follows:
blockSizeR = 50; % Rows in block.
blockSizeC = 512; % Columns in block.
wholeBlockRows = floor(rows / blockSizeR);
blockVectorR = [blockSizeR * ones(1, wholeBlockRows), rem(rows, blockSizeR)];
wholeBlockCols = floor(columns / blockSizeC);
blockVectorC = [blockSizeC * ones(1, wholeBlockCols), rem(columns, blockSizeC)];
if numberOfColorBands > 1
% It's a color image.
ca = mat2cell(rgbImage, blockVectorR, blockVectorC, numberOfColorBands);
else
ca = mat2cell(rgbImage, blockVectorR, blockVectorC);
end
% Now display all the blocks.
plotIndex = 1;
numPlotsR = size(ca, 1);
numPlotsC = size(ca, 2);
for r = 1 : numPlotsR
for c = 1 : numPlotsC
fprintf('plotindex = %d, c=%d, r=%d\n', plotIndex, c, r);
% Specify the location for display of the image.
subplot(numPlotsR, 1, plotIndex);
% Extract the numerical array out of the cell
% just for tutorial purposes.
rgbBlock = ca{r,c};
imshow(rgbBlock); % Could call imshow(ca{r,c}) if you wanted to.
[rowsB columnsB numberOfColorBandsB] = size(rgbBlock);
% Make the caption the block number.
caption = sprintf('Block #%d of %d\n%d rows by %d columns', ...
plotIndex, numPlotsR*numPlotsC, rowsB, columnsB);
title(caption);
drawnow;
% Increment the subplot to the next location.
plotIndex = plotIndex + 1;
end
end
I am new to MatLab, so is there is a simpler method to do this that I missed out, please do suggest or better still, if there are references that I can refer to. Many thanks (:
If you know the dimensions of your matrix, you can do the math to figure out how to divide the number of rows into 4 equal parts:
e.g. If: size(rockinsMatrix) == [10 20] (a 10row x 20column) matrix,
then you could split it into a set of 4 sub-matrices, two with 3 rows, and 2 with 2 columns.
If you want the matrices in a cell array then you can do that at that time.
I managed to solve already, the error lies in the for loop. I changed the for r = 1 : numPlotsR into r = 1 : (number of rows I want) for c = 1 : numPlotsC into c= 1: 1(as I only want one column), and used subplot(8,1,k) or (8,2,k) where k is the plot index. Just answering this in case anybody encounter such problem in future and want to use my code as a reference. Cheers!

Resources