MATLAB: creation of 3D array, vectorizing vs. looping - arrays

I have searched for an answer for my question on here but cannot find one, so I apologize in advance if it already exists!
What I am trying to do is create a 3D array of 3-d points in space (x,y,z). I know in a 1D vector you can specify the interval, like 1:5:20, to get a vector from 1 to 20 spaced by 5. What I would like to do is create a 3D array, most likely row by row would be the most efficient, where the spacing is by a unit vector (ix, iy, iz). so, for example,
a(1,1,:) = [1, 1, 1]
uv = [0.5 0.5 0.5]
a(2,2,:) = [1.5, 1.5, 1.5]
etc. I know the numbers are not 'unit vectors', but the idea is there. Is there something along the lines of a = [1, 1, 1] : uv : [end, end, end] ???

You might be interested in a mesh grid.

An example:
[X,Y,Z] = meshgrid(1:0.1:2, 1:0.1:2, 1:0.1:2); %# they can be different
points = [X(:) Y(:) Z(:)];
plot3(points(:,1),points(:,2),points(:,3),'.')
box on, axis equal
xlabel x, ylabel y, zlabel z

Related

Subtract 2 different sized 2D arrays to produce a 3D array

I have two 2D arrays, one M is 2000x3 and the other N is 20x3 (sets of x,y,z coords). I would like to subtract N from M to produce a 3D array 2000x20x3. Currently I get a ValueError: operands could not be broadcast together with shapes (2000,3) (20,3)
A more simple example as a working exercise
M = np.array([[1,1,1],[2,1,1],[3,1,1],[4,1,1],[1,2,1],[2,2,1],[3,2,1],[4,2,1]])
N = np.array([[0,0,0],[1,0,0]])
M.shape = (8,3)
N.shape = (2,3)
I wish to do A=M-N to produce an 8x2x3 array, where for each value 1->M, there are N sets of differences in the x,y,z coordinates.
In other words:
A = array([[[1,1,1],[0,1,1]],[[2,1,1],[1,1,1]],[[3,1,1],[2,1,1]],[[4,1,1],[3,1,1]],[[1,2,1],[0,2,1]]...])
Is this possible, and if so how? Preferably without the use of any for loops
Use broadcasting:
A = M[:,None]-N
A.shape
# (8, 2, 3)

How to collapse 2D scatter plot into a dot plot?

I have a very large 2d array of shape (186295, 2) with the first element of every 2-element sub-array being x and the second element being y. Here is how I produce the scatter plot by separating x and y components in matplotlib:
ax.scatter(A[:, 0]+np.random.uniform(-.02, .02, A.shape[0]), A[:, 1], s=2, color='b', alpha=0.5, zorder=3)
However, I would like
all points with x-value in the range [8,9.2] be shown as a dot plot at the mid point x=8.6,
all points with x-value in the range [9.2,10.4] be shown as a dot plot at the mid point x=9.8,
all points with x-value in the range [10.4,12.2] be shown as a dot plot at the mid point x=11.3.
Your help is greatly appreciated,
You can use np.select:
Example:
import numpy as np
from matplotlib import pyplot as plt
n=100
x = np.random.uniform(8, 12, n)
y = np.random.uniform(.01, 1, n)
a = np.array(list(zip(x,y)))
fig,ax = plt.subplots(2, sharex=True)
ax[0].scatter(a[:,0], a[:,1])
ax[0].title.set_text('Scatter Plot')
conditions = [a[:,0]<=8, a[:,0]<=9.2, a[:,0]<=10.4, a[:,0]<=12.2, a[:,0]>12.2]
choices = [a[:,0], 8.6, 9.8, 11.3, a[:,0]]
a[:,0] = np.select(conditions, choices)
ax[1].scatter(a[:,0], a[:,1])
ax[1].title.set_text('Dot Plot')
Result:
Another possibility is using np.digitize which saves some typing as it uses a list of bins (upper bounds) instead of a list of conditions.

Despite many examples online, I cannot get my MATLAB repmat equivalent working in python

I am trying to do some numpy matrix math because I need to replicate the repmat function from MATLAB. I know there are a thousand examples online, but I cannot seem to get any of them working.
The following is the code I am trying to run:
def getDMap(image, mapSize):
newSize = (float(mapSize[0]) / float(image.shape[1]), float(mapSize[1]) / float(image.shape[0]))
sm = cv.resize(image, (0,0), fx=newSize[0], fy=newSize[1])
for j in range(0, sm.shape[1]):
for i in range(0, sm.shape[0]):
dmap = sm[:,:,:]-np.array([np.tile(sm[j,i,:], (len(sm[0]), len(sm[1]))) for k in xrange(len(sm[2]))])
return dmap
The function getDMap(image, mapSize) expects an OpenCV2 HSV image as its image argument, which is a numpy array with 3 dimensions: [:,:,:]. It also expects a tuple with 2 elements as its imSize argument, of course making sure the function passing the arguments takes into account that in numpy arrays the rows and colums are swapped (not: x, y, but: y, x).
newSize then contains a tuple containing fracions that are used to resize the input image to a specific scale, and sm becomes a resized version of the input image. This all works fine.
This is my goal:
The following line:
np.array([np.tile(sm[i,j,:], (len(sm[0]), len(sm[1]))) for k in xrange(len(sm[2]))]),
should function equivalent to the MATLAB expression:
repmat(sm(j,i,:),[size(sm,1) size(sm,2)]),
This is my problem:
Testing this, an OpenCV2 image with dimensions 800x479x3 is passed as the image argument, and (64, 48) (a tuple) is passed as the imSize argument.
However when testing this, I get the following ValueError:
dmap = sm[:,:,:]-np.array([np.tile(sm[i,j,:], (len(sm[0]),
len(sm[1]))) for k in xrange(len(sm[2]))])
ValueError: operands could not be broadcast together with
shapes (48,64,3) (64,64,192)
So it seems that the array dimensions do not match and numpy has a problem with that. But my question is what? And how do I get this working?
These 2 calculations match:
octave:26> sm=reshape(1:12,2,2,3)
octave:27> x=repmat(sm(1,2,:),[size(sm,1) size(sm,2)])
octave:28> x(:,:,2)
7 7
7 7
In [45]: sm=np.arange(1,13).reshape(2,2,3,order='F')
In [46]: x=np.tile(sm[0,1,:],[sm.shape[0],sm.shape[1],1])
In [47]: x[:,:,1]
Out[47]:
array([[7, 7],
[7, 7]])
This runs:
sm[:,:,:]-np.array([np.tile(sm[0,1,:], (2,2,1)) for k in xrange(3)])
But it produces a (3,2,2,3) array, with replication on the 1st dimension. I don't think you want that k loop.
What's the intent with?
for i in ...:
for j in ...:
data = ...
You'll only get results from the last iteration. Did you want data += ...? If so, this might work (for a (N,M,K) shaped sm)
np.sum(np.array([sm-np.tile(sm[i,j,:], (N,M,1)) for i in xrange(N) for j in xrange(M)]),axis=0)
z = np.array([np.tile(sm[i,j,:], (N,M,1)) for i in xrange(N) for j in xrange(M)]),axis=0)
np.sum(sm - z, axis=0) # let numpy broadcast sm
Actually I don't even need the tile. Let broadcasting do the work:
np.sum(np.array([sm-sm[i,j,:] for i in xrange(N) for j in xrange(M)]),axis=0)
I can get rid of the loops with repeat.
sm1 = sm.reshape(N*M,L) # combine 1st 2 dim to simplify repeat
z1 = np.repeat(sm1, N*M, axis=0).reshape(N*M,N*M,L)
x1 = np.sum(sm1 - z1, axis=0).reshape(N,M,L)
I can also apply broadcasting to the last case
x4 = np.sum(sm1-sm1[:,None,:], 0).reshape(N,M,L)
# = np.sum(sm1[None,:,:]-sm1[:,None,:], 0).reshape(N,M,L)
With sm I have to expand (and sum) 2 dimensions:
x5 = np.sum(np.sum(sm[None,:,None,:,:]-sm[:,None,:,None,:],0),1)
len(sm[0]) and len(sm[1]) are not the sizes of the first and second dimensions of sm. They are the lengths of the first and second row of sm, and should both return the same value. You probably want to replace them with sm.shape[0] and sm.shape[1], which are equivalent to your Matlab code, although I am not sure that it will work as you expect it to.

Matlab Sparse Array Index Reassignment

Does anyone know if there is a way to do a simple reordering of the row-column positions in a sparse array in Matlab?
I have a sparse array which corresponds to the adjacency matrix of a graph that I am trying to analyze, and I would like to reorder the vertices in my graph by some calculated metric (while hopfully preserving the way that the mapping was constructed)
Does anyone have any suggestions on a way to do this? I am new to Matlab and am not yet completely familiar with all of the tools that it has for Matrix manipulations.
With a sparse matrix you assign entry values the same way as you would with a normal matrix. For example:
>> a = sparse(1:2, 3:4, [1 1], 4, 5, 7)
a =
(1,3) 1
(2,4) 1
a(1,3) = 0; a(1,2) = 1; % move the "1" from (1,3) to (1,2)
>> a
a =
(1,2) 1
(2,4) 1
You can also assign whole columns or rows. For example, this swaps columns 2 and 3:
aux = a(:,3);
a(:,3) = a(:,2);
a(:,2) = aux;

Populating array in mathematica

I have a set of around 500 (x,y,z) real values. Since I will need to bin the values based on their (x,y) coordinates, I stripped the z values and stored in on a seperate list. I am left with only the x,y values; I rescaled and rounded them to index pairs in the range of, 1..100 range.
Now I want to populate an array with the z values in a 100x100 matrix at the particular (x,y) coordinates.
More precisely,
I have a set of values for example : data = {{2.62399, 0.338057, 2.09629}, {1.8424, 0.135817, 3.21925}, {0.702257, 1.14502, 3.9335}...
I stripped it of its zvalues and store it in zvalues list:
zvalues = {2.09629, 3.21925, 3.9335....
I rounded, rescaled and created a new array of indices
indices = {{53, 7}, {37, 3}, {14, 23}...
I want to create a new 100x100 matrix and place the zvalues on the coordinates corresponding to the indices matrix
For example, in pseudocode
For (int i = 1, i < 101, i++){
NewArray(indices[i]) = zvalues[i];
}
The first time the loop will run, it should do NewArray(53,7) = 2.09629.
I want to know the syntax to loop through the indices array and populate the 2 dimensional 100x100 NewArray with zvalues
to follow your basic approach you need to initialize the array:
newArray=Table[,{100},{100}]
then in the loop the syntax is:
newArray[[indices[[i,1]],indices[[i,2]]]]=zdata[[i]]
note the double square brackets for referencing parts of arrays (or lists in Mathematica terminology)
A better approach would be to create a SparseArray, which for one thing would not require pre-initialization, or even knowing the dimensions in advance.
Finally in mathematica you can usually use an object oriented approach, avioding the "do" loop all together:
data = {{1.5, 1.1, 1.1}, {2.2, 2.2, 2.2}, {1.01, 2.3, 1.2}};
m1 = Table[, {2}, {2}];
(m1[[Floor[#[[1]]], Floor[#[[2]]]]] = #[[3]]) & /# data;
m1
m2 = SparseArray[ Floor[#[[1 ;; 2]]] -> #[[3]] & /# data , Automatic,];
Normal[m2]
{{1.1, 1.2}, {Null, 2.2}}
{{1.1, 1.2}, {Null, 2.2}}
While I don't understand why you want to create a new way of indexing your array, this will do what you want :
data = {{2.62399, 0.338057, 2.09629}, {1.8424, 0.135817, 3.21925}, {0.702257, 1.14502, 3.9335}};
zvalues = {2.09629, 3.21925, 3.9335};
indices = {{53, 7}, {37, 3}, {14, 23}};
newArray[xIndex_, yIndex_]:=Take[data, Position[indices, {xIndex, yIndex}][[1, 1]]][[1, 3]]
newArray[53, 7]
(* 2.09629 *)

Resources