Plotting from a 2D Array Using a Loop - arrays

This seems like a trivial problem, though I've been hitting myself over the head with it for too long.
This doesn't even plot just the (0,0) -- I can't seem to find much about plotting from arrays -- rather just matrix plots (and only columns at that).
The data is properly in these arrays, I just need to make plots! Doesn't seem so complicated. I don't even need separate colors for the different sets...just all one big scatter plot.
Any suggestions?
pdf(mypath)
# Plot first point
plot(0,0, col = "blue", type = "n", xlab="PES", ylab=""%eff")
#Loop to Plot remaining points
for(rows in 1:nrowX)
{
for(cols in 1:ncolX)
{
points(X[rows,cols],Y[rows,cols], col = "blue", type = "p")
}
}
dev.off
I have also tried using plot.new() to have an empty plot...but no such luck.
SOLUTION!!
Turns out I'm just a fool. Code is acurate and the suggestions below do indeed work.
R happened to be open in another tab and since it was open, never let go of the plot (why? I don't know). As soon as it was closed, the plot appeared. Now I can get my plot again and again...
Thanks to everyone who tried helping a problem that wasn't a problem!
I like this place already!

When you set type = "n", the plot function will not plot anything at all. It is used to set up a basis for the rest of the plot (like axis labels, limits etc). That is why the first point at (0, 0) does not show up.
The rest of the points are probably outside the range. Use xlim and ylim to set up the ranges properly. I'm going to assume X and Y have the same size and dimension. Try this:
pdf(mypath)
# Set up the plot
plot(0, type="n", xlab="PES", ylab="%eff", xlim=range(X), ylim=range(y))
# Now plot
points(X,Y, col="blue")
dev.off
Of course you could let the plot function take care of the limits for you:
pdf(mypath)
plot(X, Y, xlab="PES", ylab="%eff")
dev.off()

Your initial plot will set up the coordinates, but since you only give it one point it does not know how much room to leave around the 0,0 point (so it does not leave very much). I expect that the rest of your points fall outside of that range which is why they don't show up on the plot (you can use par("usr") to see what the extents are).
When you create the initial plot you should include xlim and ylim arguments so that the plot includes the area where the new points will be added, something like:
plot(0,0, type='n', xlim=range(X), ylim=range(Y))
You may also be interested in the matplot function which will take a matrix as either or both the x and/or y argument and plot accordingly.
Edit
The following works for me:
X <- matrix( runif(390), nrow=10 )
Y <- matrix( rnorm(390), nrow=10 )
plot(0,0, col = "blue", type = "n", xlab="PES", ylab="%eff",
xlim=range(X), ylim=range(Y))
#Loop to Plot remaining points
for(rows in 1:nrow(X))
{
for(cols in 1:ncol(X))
{
points(X[rows,cols],Y[rows,cols], col = "blue", type = "p")
}
}
I did remove an extra " from the ylab, was that your problem?
But
plot(X,Y)
also worked without the looping.
Check with just the console to see if it works before worrying about sending to a pdf file. If this has not fixed it yet, we still need more details.

Related

FiPy: Can I directly change faceVariables depending on neighboring cells?

I am working with a biological model of the distribution of microbial biomass (b1) on a 2D grid. From the biomass a protein (p1) is produced. The biomass diffuses over the grid, while the protein does not. Only if a certain amount of protein is produced (p > p_lim), the biomass is supposed to diffuse.
I try to implement this by using a dummy cell variable z multiplied with the diffusion coefficient and setting it from 0 to 1 only in cells where p > p_lim.
The condition works fine and when the critical amount of p is reached in a cell, z is set to 1, and diffusion happens. However, the diffusion still does not work with the rate I would like, because to calculate diffusion, the face variable, not the value of the cell itself is used. The faces of z are always a mean of the cell with z=1 and its neighboring cells with z=0. I I, however, would like the diffusion to work at its original rate even if the neighbouring cell is still at p < p_lim.
So, my question is: Can i somehow access a faceVariable and change it? For example, set a face to 1 if any neigboring cell has reached p1 > p_lim? I guess this is not a proper mathematical thing to do, but I couldn't think of another way to simulate this problem.
I will show a very reduced form of my model below. In any case, I thank you very much for your time!
##### produce mesh
nx= 5.
ny= nx
dx = 1.
dy = dx
L = nx*dx
mesh = Grid2D(nx=nx,ny=ny,dx=dx,dy=dy)
#parameters
h1 = 0.5 # production rate of p
Db = 10. # diffusion coeff of b
p_lim=0.1
# cell variables
z = CellVariable(name="z",mesh=mesh,value=0.)
b1 = CellVariable(name="b1",mesh=mesh,hasOld=True,value=0.)
p1= CellVariable(name="p1",mesh=mesh,hasOld=True,value=0.)
# equations
eqb1 = (TransientTerm(var=b1)== DiffusionTerm(var=b1,coeff=Db*z.arithmeticFaceValue)-ImplicitSourceTerm(var=b1,coeff=h1))
eqp1 = (TransientTerm(var=p1)==ImplicitSourceTerm(var=b1,coeff=h1))
# set b1 to 10. in the center of the grid
b1.setValue(10.,where=((x>2.)&(x<3.)&(y>2.)&(y<3.)))
vi=Viewer(vars=(b1,p1),FIPY_VIEWER="matplotlib")
eq = eqb1 & eqp1
from builtins import range
for t in range(10):
b1.updateOld()
p1.updateOld()
z.setValue(z + 0.1,where=((p1>=p_lim) & (z < 1.)))
eq.solve(dt=0.1)
vi.plot()
In addition to .arithmeticFaceValue, FiPy provides other interpolators between cell and face values, such as .harmonicFaceValue and .minmodFaceValue.
These properties are implemented using subclasses of _CellToFaceVariable, specifically _ArithmeticCellToFaceVariable, _HarmonicCellToFaceVariable, and _MinmodCellToFaceVariable.
You can also make a custom interpolator by subclassing _CellToFaceVariable. Two such examples are _LevelSetDiffusionVariable and ScharfetterGummelFaceVariable (neither is well documented, I'm afraid).
You need to override the _calc_() method to provide your custom calculation. This method takes three arguments:
alpha: an array of the ratio (0-1) of the distance from the face to the cell on one side, relative to the distance from distance from the cell on the other side to the cell on the first side
id1: an array of indices of the cells on one side of the face
id2: an array of indices of the cells on the other side of the face
Note: You can ignore any clause if inline.doInline: and look at the _calc_() method defined under the else: clause.

Interpolate 2D Array to single point in MATLAB

I have 3 graphs of an IV curve (monotonic increasing function. consider a positive quadratic function in the 1st quadrant. Photo attached.) at 3 different temperatures that are not obtained linearly. That is, one is obtained at 25C, one at 125C and one at 150C.
What I want to make is an interpolated 2D array to fill in the other temperatures. My current method to build a meshgrid-type array is as follows:
H = 5;
W = 6;
[Wmat,Hmat] = meshgrid(1:W,1:H);
X = [1:W; 1:W];
Y = [ones(1,W); H*ones(1,W)];
Z = [vecsatIE25; vecsatIE125];
img = griddata(X,Y,Z,Wmat,Hmat,'linear')
This works to build a 6x6 array, which I can then index one row from, then interpolate from that 1D array.
This is really not what I want to do.
For example, the rows are # temps = 25C, 50C, 75C, 100C, 125C and 150C. So I must select a temperature of, say, 50C when my temperature is actually 57.5C. Then I can interpolate my I to get my V output. So again for example, my I is 113.2A, and I can actually interpolate a value and get a V for 113.2A.
When I take the attached photo and digitize the plot information, I get an array of points. So my goal is to input any Temperature and any current to get a voltage by interpolation. The type of interpolation is not as important, so long as it produces reasonable values - I do not want nearest neighbor interpolation, linear or something similar is preferred. If it is an option, I will try different kinds of interpolation later (cubic, linear).
I am not sure how I can accomplish this, ideally. The meshgrid array does not need to exist. I simply need the 1 value.
Thank you.
If I understand the question properly, I think what you're looking for is interp2:
Vq = interp2(X,Y,V,Xq,Yq) where Vq is the V you want, Xq and Yq are the temperature and current, and X, Y, and V are the input arrays for temperature, current, and voltage.
As an option, you can change method between 'linear', 'nearest', 'cubic', 'makima', and 'spline'

Plotting arrays using a grouped horizontal bar graph

I am trying to generate a graph that should look similar to:
My arrays are:
Array4:[Nan;Nan;.......;20;21;22;23;24;..........60]
Array3:[[Nan;Nan;.......;20;21;22;23;24;..........60]
Array2:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
Array1:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
I cannot find the right way to group my arrays in order to plot them in the way shown on the above graph.
I tried using the following function explained in: http://uk.mathworks.com/help/matlab/ref/barh.html
barh(1:numel(x),y,'hist')
where y=[Array1,Array2;Array3,Array4] and x={'1m';'2m';'3m';......'60m'}
but it does not work.
Why Your Current Approach Isn't Working
Your intuition makes sense to me, but the barh function you are using doesn't work the way you think it does. Specifically, you are interpreting the meaning of the x and y inputs to that function incorrectly. Those are inputs are constant values, not entire axes. The first y input refers to the end-point of the bar that stretches horizontally from x = 0 and the first x input refers to location on the y-axis of the horizontal bar. To illustrate what I mean, I've provided the below horizontal bar graph:
You can find this same picture in the official documentation of the MATLAB barh function. The code used to generate this bar graph is also given in the documentation, shown below:
x = 1900:10:2000;
y = [57,91,105,123,131,150,...
170,203,226.5,249,281.4];
figure;
barh(x, y);
The individual elements of the x array, rather confusingly, show up on the y-axis as the starting locations of each bar. The corresponding elements of the y array are the lengths of each bar. This is the reason that the arrays must be the same length, and this illustrates that they are not specifications of the x and y axes as one might intuitively believe.
An Approach To Solve Your Problem
First things first, the easiest approach is to do this manually with the plot function and a set of lines that represent floating bars. Consult the official documentation for the plot function if you'd like to plot the lines with some sort of color coordination in mind - the code I present (modified version of this answer on StackOverflow) just switches the color of the floating bars between red and blue. I tried to comment the code so that the purpose of each variable is clear. The code I present below matches the floating bar graph that you want to be plotted, if you are alright with replacing thick floating bars with 2D lines floating on a plot.
I used the data that you gave in your question to specify the floating horizontal bars that this script would output - a screenshot is shown below the code. Array1 & Array2:[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60], these arrays go from 0 to 6 (length = 6) and 17 to 60 (length = 60 - 17 = 43). Because there is a "discontinuity" of sorts from 7 to 16, I have to define two floating bars for each array. Hence, the first four values in my length array are [6, 6, 43, 43]. Where the first 6 and the first 43 correspond to Array1 and the second 6 and the second 43 correspond to Array2. Recognizing this "discontinuity", the starting point of the first floating bar for Array1 and Array2 is x = 0 and the starting point of the second floating bar for Array1 and Array2 is x = 7. Putting that all together, you arrive at the x-coordinates for the first four points in the floating_bars array, [0 0; 0 1.5; 17 0; 17 1.5]. The y-coordinates in this array only serve to distinguish Array1, Array2, and so on from each other.
Code:
floating_bars=[0 0; 0 1.5; 17 0; 17 1.5; 20 6; 20 7.5]; % Each row is the [x,y] coordinate pair of the starting point for the floating bar
L=[6, 6, 43, 43, 40, 40]; % Length of each consecutive bar
thickness = 0.75;
figure;
for i=1:size(floating_bars,1)
curr_thickness = 0;
% It is aesthetically pleasing to have thicker bars, this makes the plot look for like the grouped horizontal bar graph that you want
while (curr_thickness < thickness)
% Each bar group has two bars; set the first to be red, the second to be blue (i.e., even index means red bar, odd index means blue bar)
if mod(i, 2)
plot([floating_bars(i,1), floating_bars(i,1)+L(i)], [floating_bars(i,2) + curr_thickness, floating_bars(i,2) + curr_thickness], 'r')
else
plot([floating_bars(i,1), floating_bars(i,1)+L(i)], [floating_bars(i,2) + curr_thickness, floating_bars(i,2) + curr_thickness], 'b')
end
curr_thickness = curr_thickness + 0.05;
hold on % Make sure that plotting the current floating bar does not overwrite previous float bars that have already been plotted
end
end
ylim([ -10 30]) % Set the y-axis limits so that you can see more clearly the floating bars that would have rested right on the x-axis (y = 0)
Output:
How Do I Do This With the barh Function?
The short answer is that you'd have to modify the function manually. Someone has already done this with one of the bar graph plotting functions provided by MATLAB, bar3. The logic implemented in this modified bar3 function can be re-applied for your purposes if you read their barNew.m function and tweak it a bit. If you'd like a pointer as to where to start, I'd suggest looking at how they specify z-axis minimum and maximums for their floating bars on the plot, and apply that same logic to specify x-axis minimum and maximums for your floating bars in your 2D case.
I hope this helps, happy coding! :)
I explain here my approach to generate these type of graphs. Not sure if it is the best but it works and there is no need to do anything manually. I came up with this solution based on the following Vladislav Martin's explained fact: "The y-coordinates in this array only serve to distinguish Array1, Array2, and so on from each other".
My original arrays are:
Array4=[Nan....;20;21;22;23;24;..........60]
Array3=[Nan....;20;21;22;23;24;..........60]
Array2=[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
Array1=[0;1;2;3;4;5;6;Nan;Nan;Nan;Nan;17;18;.....60]
x={'0m';'1m';'2m';'3m';'4m';....'60m'}
The values contained in these arrays make reference to the x-axis on the graph. In order to make the things more simple and to avoid having to code a function to determine the length for each discontinuity in the arrays, I replace these values for y-axis position values. Basically I give to Array1 y-axis position values of 0 and to Array2 0+0.02=0.02. To Array3 I give y-axis position values of 0.5 and to Array4 0.5+0.02=0.52. In this way, Array2 will be plotted on the graph closer to Array1 which will form the first group and Array4 closer to Array3 which will form the second group.
Datatable=table(Array1,Array2,Array3,Array4);
cont1=0;
cont2=0.02;
for col=1:2:size(Datatable,2)
col2=col+1;
for row=1:size(Datatable,1)
if isnan(Datatable{row,col})==0 % For first array in the group: If the value is not nan, I replace it for the corresponnding cont1 value
Datatable{row,col}=cont1;
end
if isnan(Datatable{row,col2})==0 % For second array in the group: If the value is not nan, I replace it for the corresponnding cont2 value
Datatable{row,col2}=cont2;
end
end
cont1=cont1+0.5;
cont2=cont2+0.5;
end
The result of the above code will be a table like the following:
And now I plot the Arrays using 2D floating lines:
figure
for array=1:2:size(Datatable,2)
FirstPair=cell2mat(table2cell(Datatable(:,array)));
SecondPair=cell2mat(table2cell(Datatable(:,array+1)));
hold on
plot(1:numel(x),FirstPair,'r','Linewidth',6)
plot(1:numel(x),SecondPair,'b','Linewidth',6)
hold off
end
set(gca,'xticklabel',x)
And this will generate the following graph:

Split array into smaller unequal-sized arrays dependend on array-column values

I'm quite new to MatLab and this problem really drives me insane:
I have a huge array of 2 column and about 31,000 rows. One of the two columns depicts a spatial coordinate on a grid the other one a dependent parameter. What I want to do is the following:
I. I need to split the array into smaller parts defined by the spatial column; let's say the spatial coordinate are ranging from 0 to 500 - I now want arrays that give me the two column values for spatial coordinate 0-10, then 10-20 and so on. This would result in 50 arrays of unequal size that cover a spatial range from 0 to 500.
II. Secondly, I would need to calculate the average values of the resulting columns of every single array so that I obtain per array one 2-dimensional point.
III. Thirdly, I could plot these points and I would be super happy.
Sadly, I'm super confused since I miserably fail at step I. - Maybe there is even an easier way than to split the giant array in so many small arrays - who knows..
I would be really really happy for any suggestion.
Thank you,
Arne
First of all, since you wish a data structure of array of different size you will need to place them in a cell array so you could try something like this:
res = arrayfun(#(x)arr(arr(:,1)==x,:), unique(arr(:,1)), 'UniformOutput', 0);
The previous code return a cell array with the array splitted according its first column with #(x)arr(arr(:,1)==x,:) you are doing a function on x and arrayfun(function, ..., 'UniformOutput', 0) applies function to each element in the following arguments (taken a single value of each argument to evaluate the function) but you must notice that arr must be numeric so if not you should map your values to numeric values or use another way to select this values.
In the same way you could do
uo = 'UniformOutput';
res = arrayfun(#(x){arr(arr(:,1)==x,:), mean(arr(arr(:,1)==x,2))), unique(arr(:,1)), uo, 0);
You will probably want to flat the returning value, check the function cat, you could do:
res = cat(1,res{:})
Plot your data depends on their format, so I can't help if i don't know how the data are, but you could try to plot inside a loop over your 'res' variable or something similar.
Step I indeed comes with some difficulties. Once these are solved, I guess steps II and III can easily be solved. Let me make some suggestions for step I:
You first define the maximum value (maxValue = 500;) and the step size (stepSize = 10;). Now it is possible to iterate through all steps and create your new vectors.
for k=1:maxValue/stepSize
...
end
As every resulting array will have different dimensions, I suggest you save the vectors in a cell array:
Y = cell(maxValue/stepSize,1);
Use the find function to find the rows of the entries for each matrix. At each step k, the range of values of interest will be (k-1)*stepSize to k*stepSize.
row = find( (k-1)*stepSize <= X(:,1) & X(:,1) < k*stepSize );
You can now create the matrix for a stepk by
Y{k,1} = X(row,:);
Putting everything together you should be able to create the cell array Y containing your matrices and continue with the other tasks. You could also save the average of each value range in a second column of the cell array Y:
Y{k,2} = mean( Y{k,1}(:,2) );
I hope this helps you with your task. Note that these are only suggestions and there may be different (maybe more appropriate) ways to handle this.

Matlab - Cropping 2d image maps in a loop and storing in a single variable

I have a code to crop connected components of input image, input, by finding the boundary conditions from a binary image's labelled map, labelledmap ([labelledmap, labelcount] = bwlabel(hvedged, 8);)
I'm new to matlab so this might sound stupid..
The problem is, I am unable to store different cropped images in the same variable, Because matlab seems to merge the ends of the already existing image and the new cropped image, i.e, it is storing the complete map between the two cropped images, the way i see it :/
This is the output Using different variables for storing cropped image (the kind of output i want)
Output Using different variables for storing cropped image
This is the output i'm getting by storing the cropped image in the same variable(not helpful)
Output when storing cropped image in the same varible
I tried using an array of size equal to total number of labels produced but it's giving the same result.. also i tried clearvars for clearing the output token image, ltoken, after every iteration of the loop but it's not helping
So, is there any possible way to display individual cropped images.. also the number of cropped images might be in thousands so i want to use a loop to code their cropping mechanism
here is a part of the code attached.. thanks in advance ;)
for h=1:labelcount
for i=1:r
for j=1:c
if labelledmap(i,j)==h
if i<ltop
ltop=i;
end
if i>lbottom
lbottom=i;
end
if j<lleft
lleft=j;
end
if j>lright
lright=j;
end
end
end
end
if ltop>5
ltop=ltop-5;
end
if lbottom<r-5
lbottom=lbottom+5;
end
if lleft>5
lleft=lleft-5;
end
if lright<c-5
lright=lright+5;
end
lwidth=lright-lleft;
lheight=lbottom-ltop;
ltoken=imcrop(input,[lleft ltop lwidth lheight]);
figure('Name', 'Cropped Token'), imshow(ltoken);
clearvars ltoken;
end
you need to initialize ltop lbottom lleft and lright for each iteration of label h. I think this is the reason why you get the cropped images "glued" together.
It is EXTREMELY inefficient to go through all the pixels for each and every one of your labels. Especially when you are expected to have many labels.
Use regionprops to get the 'BoundingBox' property for each label.
Here's an example
st = regionprops( labelledmap, 'BoundingBox' );
imlist = cell( 1, numel(st) ); % pre-allocate
for ii=1:numel(st)
r = st(ii).BoundingBox;
% I understand you want to increase the BB by 5 pixels at each side:
r(1:2) = r(1:2) - 5; % start point moves -5
r(3:4) = r(3:4) + 10; % width and height increases by 10
imlist{ii} = imcrop( input, r );
end
I'm still a bit in shock by your code that explicitly loops through all pixels just for finding the bouding box. This is NOT the matlab way of doing things.
If you insist on NOT using regionprops here's a more Matlab-ish way of finding the ii-th bounding box:
imsk = (labeledmap == ii); % create a binary map with True for ii-th region
xFlat = any(imsk,1); % "flattening" imsk on the x-axis
lleft = find( xFlat, 1, 'first' );
lright = find( xFlat, 1, 'last' );
yFlat = any(imsk, 2);
ltop = find( yFlat, 1, 'first' );
lbottom = find( yFlat, 1, 'last' );
No loops at all over image coordinates.

Resources