I use a data set called: arr0 with dimensions: (x, y, t) = (151, 151, 600). To create a 2D image I took a specific y-coordinate with slicing i.e. arr0[:,0], now the dimensions are: (x, t) = (151, 600). Within the dataset arr0[:,0] there are x-values for a time greater than t = 0.00173 (below the blue line in the image and last line of code, both shown below). What I would like to do is zero out all x-values for t > 0.00173.
The problem is that I don't know how I should do this, could someone please help me?
Best,
FR
plt.figure(figsize = (10,10))
plt.subplots_adjust(wspace=0.3)
plt.subplot(121)
plt.imshow((np.rot90(arr0[:,0],3)),cmap='Greys',extent=[xr1,xr2,taxis[nt-1],taxis[0]],aspect='auto')
plt.xlabel("Xr location [m]")
plt.ylabel("Time [s]")
plt.title("Direct wave after extrap (arr0)")
plt.hlines(0.00173,-0.3,0.3)
2D graph with values I want to turn zero below the blue line
If I understand you correctly, we can regard x, y, t as index variables along the axes of your 3-dimensional array, which contains the actual data values (represented by grayscale pixels in the plot). Here is a simplified example:
import numpy as np
import matplotlib.pyplot as plt
arr0 = np.array([[[0, 2, 1, 1, 2, 2],
[0, 2, 1, 1, 2, 2]],
[[0, 3, 1, 1, 2, 2],
[0, 3, 1, 1, 2, 2]]])
arr0.shape
(2, 2, 6)
Now I suppose you don't want to set the x values to zero, but rather the actual data values. Since NumPy works with integer indices, you'll have to convert your t-threshold to the appropriate integer index, based on the range of t values and the length of the array in dimension t:
plt.figure(figsize = (10, 4))
plt.subplots_adjust(wspace=0.3)
# plot original data slice
plt.subplot(121)
plt.imshow((np.rot90(arr0[:,0],3)), cmap='Greys', aspect='auto')
# define t-threshold integer index based on t range
t_threshold = int(arr0.shape[2] * 0.00173 / 0.006) + 1
# clean up data by setting values above t-threshold to zero
arr0[:, 0, t_threshold:] = 0
# plot cleaned up data slice
plt.subplot(122)
plt.imshow((np.rot90(arr0[:,0],3)), cmap='Greys', aspect='auto');
Note that assigning new values to the slice has changed the full array accordingly:
arr0
array([[[0, 2, 0, 0, 0, 0],
[0, 2, 1, 1, 2, 2]],
[[0, 3, 0, 0, 0, 0],
[0, 3, 1, 1, 2, 2]]])
Related
I have multiple 3D arrays with different shapes but I'm going to assume I have an array named A with shape (53, 768, 768) for an example. It consists of 53 2D arrays and some of them may be empty images. Those empty images have only 0 pixel values.
If there are N slices with all 0 values, I want to slice A into a (53 - N, 768, 768) 3D array. Is this possible with indexing?
I tried something like this a[:, ~np.all(a == 0)], but it returns an array with shape (53, 1, 768, 768).
Let's assume your data is something like this:
z = np.array([
[[1, 2, 3], [4, 5, 6]],
[[7, 8, 9], [10, 11, 12]],
[[0, 0, 0], [0, 0, 0]],
[[1, 1, 1], [1, 1, 1]]
])
The shape of z is (4, 2, 3). We therefore need a vector with shape 4, aggregating over the other dimensions. We can use the axis= parameter in most Numpy functions for this:
mask = np.all(z != 0, axis=(1, 2))
a[mask]
In this example, mask will be array([False, False, True, False]).
Axes are numbered 0, 1, 2, etc. So we use 1 and 2 to refer to the 2nd and 3rd axes.
You can also use negative numbers as in the other answer; if you write axis=(-2, -1) that refers to the last and 2nd-to-last axes, i.e. axes 1 and 2 in this example.
In general, use axis= to specify which axes are to be collapsed by aggregating. Any axis not specified in axis= will not be aggregated.
Use:
import numpy as np
A = np.array(A) # if A is not a NumPy array
result = A[np.sum(A, axis = (-1, -2)) != 0]
This will do.
I have this 2d array of zeros z and this 1d array of starting points starts. In addition, I have an 1d array of offsets
z = z = np.zeros(35, dtype='i').reshape(5, 7)
starts = np.array([1, 5, 3, 0, 3])
offsets = np.arange(5) + 1
I would like to vectorize this little for loop here, but I seem to be unable to do it.
for i in range(z.shape[0]):
z[i, starts[i]:] += offsets[i]
The result in this example should look like this:
z
array([[0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 2, 2],
[0, 0, 0, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4],
[0, 0, 0, 5, 5, 5, 5]])
We could use some masking and NumPy broadcasting -
mask = starts[:,None] <= np.arange(z.shape[1])
z[mask] = np.repeat(offsets, mask.sum(1))
We could play a trick of broadcasted multiplication to get the final output -
z = offsets[:,None] * mask
Other way would be to assign values into z from offsets and then mask out the rest of mask, like so -
z[:] = offsets[:,None]
z[~mask] = 0
And other way would be have a replicated version from offsets as the starting z and then mask out -
z = np.repeat(offsets,z.shape[1]).reshape(z.shape[0],-1)
z[~mask] = 0
Of course, we would need the shape parameters before-hand.
If z is not initialized as zeros array, then only one of the solutions mentioned earlier would be applicable and that would need to be updated with +=, like so -
z[mask] += np.repeat(offsets, mask.sum(1))
Hi I have a list flat which is length 2800, it contains 100 results for each of 28 variables: Below is an example of 4 results for 2 variables
[0,
0,
1,
1,
2,
2,
3,
3]
I would like to reshape the list to an array (2,4) so that the results for each variable are in a single element.
[[0,1,2,3],
[0,1,2,3]]
You can think of reshaping that the new shape is filled row by row (last dimension varies fastest) from the flattened original list/array.
If you want to fill an array by column instead, an easy solution is to shape the list into an array with reversed dimensions and then transpose it:
x = np.reshape(list_data, (100, 28)).T
Above snippet results in a 28x100 array, filled column-wise.
To illustrate, here are the two options of shaping a list into a 2x4 array:
np.reshape([0, 0, 1, 1, 2, 2, 3, 3], (4, 2)).T
# array([[0, 1, 2, 3],
# [0, 1, 2, 3]])
np.reshape([0, 0, 1, 1, 2, 2, 3, 3], (2, 4))
# array([[0, 0, 1, 1],
# [2, 2, 3, 3]])
You can specify the interpretation order of the axes using the order parameter:
np.reshape(arr, (2, -1), order='F')
Step by step:
# import numpy library
import numpy as np
# create list
my_list = [0,0,1,1,2,2,3,3]
# convert list to numpy array
np_array=np.asarray(my_list)
# reshape array into 4 rows x 2 columns, and transpose the result
reshaped_array = np_array.reshape(4, 2).T
#check the result
reshaped_array
array([[0, 1, 2, 3],
[0, 1, 2, 3]])
The answers above are good. Adding a case that I used.
Just if you don't want to use numpy and keep it as list without changing the contents.
You can run a small loop and change the dimension from 1xN to Nx1.
tmp=[]
for b in bus:
tmp.append([b])
bus=tmp
It maybe not efficient in case of very large numbers. But it works for small set of numbers.
Thanks
I have an adjacency matrix of a bipartite graph (of 1's and 0's) and bi-clusters (array of arrays of rows and columns) for this matrix. How do I set different colours for elements (only 1's) in adjacency matrix which belong to different clusters with matplotlib matshow?
import numpy as np
import matplotlib.pyplot as plt
a_matrix = np.array([[0, 0, 1, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 0, 0, 0], [0, 1, 0, 0 ,0]])
cluster_1 = np.array([[1, 2, 3], [3, 4, 5]])
cluster_2 = np.array([[4, 5], [1, 2]])
# plot matrix with one colour
plt.matshow(a_matrix, cmap='Greys', interpolation='nearest')
Adjacency matrix, bi-clusters, and a bipartite graph:
One approach might be to make a copy of your matrix and then give distinct values to the clusters you identify.
m = a_matrix.copy() # a copy we can change without altering the orignal
c = cluster_1 # an alias to save typing
# Naked NumPy doesn't seem to have a cartesian product, so roll our own
for i in range(c.shape[1]):
for j in range(c.shape[1]):
if m[c[0,i]-1,c[1,j]-1]:
m[c[0,i]-1,c[1,j]-1] = 2
plt.matshow(m, cmap='jet', interpolation='nearest')
plt.show()
For more clusters, loop over the above, setting a distinct value for each cluster (and maybe choose or define a better colormap). I'm sure there are more efficient implementations of the cartesian product as well...
Ok, so I feel like there should be an easy way to create a 3-dimensional scatter plot using matplotlib. I have a 3D numpy array (dset) with 0's where I don't want a point and 1's where I do, basically to plot it now I have to step through three for: loops as such:
for i in range(30):
for x in range(60):
for y in range(60):
if dset[i, x, y] == 1:
ax.scatter(x, y, -i, zdir='z', c= 'red')
Any suggestions on how I could accomplish this more efficiently? Any ideas would be greatly appreciated.
If you have a dset like that, and you want to just get the 1 values, you could use nonzero, which "returns a tuple of arrays, one for each dimension of a, containing the indices of the non-zero elements in that dimension.".
For example, we can make a simple 3d array:
>>> import numpy
>>> numpy.random.seed(29)
>>> d = numpy.random.randint(0, 2, size=(3,3,3))
>>> d
array([[[1, 1, 0],
[1, 0, 0],
[0, 1, 1]],
[[0, 1, 1],
[1, 0, 0],
[0, 1, 1]],
[[1, 1, 0],
[0, 1, 0],
[0, 0, 1]]])
and find where the nonzero elements are located:
>>> d.nonzero()
(array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2]), array([0, 0, 1, 2, 2, 0, 0, 1, 2, 2, 0, 0, 1, 2]), array([0, 1, 0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 1, 2]))
>>> z,x,y = d.nonzero()
If we wanted a more complicated cut, we could have done something like (d > 3.4).nonzero() or something, as True has an integer value of 1 and counts as nonzero.
Finally, we plot:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, -z, zdir='z', c= 'red')
plt.savefig("demo.png")
giving
If you wanted to avoid using the nonzero option (for example, if you had a 3D numpy array whose values were supposed to be the color values of the data points), you could do what you do, but save some lines of code by using ndenumerate.
Your example might become:
for index, x in np.ndenumerate(dset):
if x == 1:
ax.scatter(*index, c = 'red')
I guess the point is just that you dont need to have nested for loops to iterate through multidimensional numpy arrays.