Filtering a numpy meshgrid - python

I would like to filter the values of a numpy meshgrid:
X,Y = np.mgrid[-10:10,-10:10]
in this case, I would like to remove all coordinates for which x**2 + y**2 <= 2. However, when I try to filter the array directly, for example
filter(lambda x,y: x**2 + y**2 >= 2, np.meshgrid[-10:10,-10:10])
I get errors because I'm not properly dealing with the array's structure.
Any tips for doing this right would be appreciated!

I was able to achieve the result that I needed using numpy.where, by filtering each array individually, but referencing both in the where condition:
X,Y = np.mgrid[-10:10,-10:10]
X,Y = np.where(X**2 + Y**2 > 2, X, 0), np.where(X**2 + Y**2 > 2, Y, 0)
This results in new 2D arrays, which is what I needed for matplotlib. Thanks to everyone who took the time to look at this question!

X,Y = np.mgrid[-10:10,-10:10]
idx = (X**2 + Y**2 > 2)
X, Y = X[idx], Y[idx]
The problem is that you no longer have 2D arrays, which may be an issue for things like matplotlib.
Seeing your own answer, and that you basically want to replace with 0 entries not fulfilling the condition, it is probably going to be cleaner and more efficient to do:
idx = X**2 + Y**2 > 2
X[~idx] = 0
Y[~idx] = 0

Related

How to make points representing a 2D line denser in Python

# imports
import numpy as np
import matplotlib.pyplot as plt
Problem
I have a 2 arrays, representing datapoints on a line. For example:
x = np.array([0,1,2])
y = np.array([5,6,4])
Plot the data:
plt.plot(x,y)
plt.scatter(x,y,c='r')
Get:
I'd like to have arrays where the datapoints represent the same lines as above, but they are doubled. The desired result is:
new_x = np.array([0,0.5,1,1.5,2]) # this is the result I am looking for
new_y = np.array([5,5.5,6,5,4]) # this is the result I am looking for
Plot:
plt.plot(new_x,new_y)
plt.scatter(new_x,new_y,c='r')
Result:
My attempt
My method of doing this:
x = np.array([0,1,2])
y = np.array([5,6,4])
new_x=[]
for index, each in enumerate(x):
if index!=0:
new_x.append((each+x[index-1])/2)
new_y=[]
for index, each in enumerate(y):
if index!=0:
new_y.append((each+y[index-1])/2)
new_x.extend(x)
new_y.extend(y)
Plot:
plt.plot(new_x,new_y)
plt.scatter(new_x,new_y,c='r')
Result:
Points are in the right place, the new points added are the correct points, but they are put into the new_x & new_y arrays in the wrong order. It is fixable by paying more attention to the .extend, but this does not seem a good method to me anyway, because of the iteration.
My research
linear interpolation between two data points: doesn't use 2D arrays
How to write a function that returns an interpolated value (pandas dataframe)?: deals with interpolated values of functions, not resampling lines as above
And there are some other questions with the [interpolation] tag, but I haven't found one descibing this problem above.
Question
How do I get the above described new_x and new_y, preferably without iteration?
You could use these one-liner list comprehensions:
new_x = [j for i, v in enumerate(x) for j in [v, (x[i] + x[(i + 1 if (len(x) - 1) != i else i)]) / 2]]
new_y = [j for i, v in enumerate(y) for j in [v, (y[i] + y[(i + 1 if (len(y) - 1) != i else i)]) / 2]]
plt.plot(new_x, new_y)
plt.scatter(new_x, new_y, c='r')
plt.show()
Output:

Create a matrix using values from a tuple with numpy

I'm trying to create a matrix with values based on x,y values I have stored in a tuple. I use a loop to iterate over the tuple and perform a simple calculation on the data:
import numpy as np
# Trying to fit quadratic equation to the measured dots
N = 6
num_of_params = 3
# x values
x = (1,4,3,5,2,6)
# y values
y = (3.96, 24.96,14.15,39.8,7.07,59.4)
# X is a matrix N * 3 with the x values to the power of {0,1,2}
X = np.zeros((N,3))
Y = np.zeros((N,1))
print X,"\n\n",Y
for i in range(len(x)):
for p in range(num_of_params):
X[i][p] = x[i]**(num_of_params - p - 1)
Y[i] = y[i]
print "\n\n"
print X,"\n\n",Y
Is this can be achieved in an easier way? I'm looking for some way to init the matrix like X = np.zeros((N,3), read_values_from = x)
Is it possible? Is there another simple way?
Python 2.7
Extend array version of x to 2D with a singleton dim (dim with length=1) along the second one using np.newaxis/None. This lets us leverage NumPy broadcasting to get the 2D output in a vectorized manner. Similar philosophy for y.
Hence, the implementation would be -
X = np.asarray(x)[:,None]**(num_of_params - np.arange(num_of_params) - 1)
Y = np.asarray(y)[:,None]
Or use the built-in outer method for np.power to get X that takes care of the array conversion under the hoods -
X = np.power.outer(x, num_of_params - np.arange(num_of_params) - 1)
Alternatively, for Y, use np.expand_dims -
Y = np.expand_dims(y,1)

ask for help for a sum (sigma) function

need help to calculate this:
so, the total number of y is equal to number of x, and each y is calculated with one x and several a.
My code list below, it gives the correct results for a0. what is a simple way to calculate this? maybe a different version can also verify the results.
Thanks a lot.
import numpy as np
import matplotlib.pyplot as plt
a = np.array([1,2,3,4],float) # here we can give several a
b = np.asarray(list(enumerate(a)))
x = np.linspace(0.0,1.0,10)
y1 = []
for r in x:
y1.append(np.exp(np.sum((1-r)**2*a*((2*b[:,0]+1)*r-1+r)*(r-1+r)**(b[:,0]-1))))
y1=np.asarray(y1)
You can write almost literally the same in numpy:
def f(x, a):
x, a = np.asanyarray(x), np.asanyarray(a)
x = x[:, None] # create new dimension to sum along
i = np.arange(len(a)) # create counter
return np.sum((1-x)**2 * a * ((2*i + 1) * x - (1-x)) * (x - (1-x))**(i-1), axis=-1)
As a side note: there are obvious algebraic simplifications you could take advantage of.

Combining different elements of array in Numpy while doing vector operations

I have a function f which I am using to evolve a Numpy array z repeatedly. Thus my code looks like this:
for t in range(100):
z = f(z)
However, now I want to combine elements of array while evolving. For example, in simple Python, I would like to do something like this:
N = len(z)
for t in range(100):
for i in range(len(z)):
z_new[i] = f(z[i]) + z[(i-1)%N] + z[(i+1)%N]
z = z_new
How can achieve the same thing in Numpy vector operations so that I wouldn't have to compromise with the great speed that Numpy gives me?
Thanks in advance
You can roll the data back and forth to achieve the same result.
Z = f(z)
Z = np.roll(Z, 1) + z
Z = np.roll(Z, -2) + z
z = np.roll(Z, 1)
I had also first thought about slicing but went with np.roll when I found it.
Prompted by #hpaulj's comment I came up with a slice solution:
q = np.array([1,2,3,4,5])
Q = f(q)
# operate on the middle
Q[1:] += q[:-1]
Q[:-1] += q[1:]
# operate on the ends
Q[0] += q[-1]
Q[-1] += q[0]
q = Q.copy()

Assigning input markers to function output in python

Sorry for the seemingly elementary question. What I'm trying to implement is summarized in the following steps:
Generate input variables: x, y.
Let z = F(x,y).
Plot z's for particular combinations of x and y.
For example:
zlist = []
for _ in range(100):
x = np.random.random()*1.
y = np.random.random()*.5
if x < .5:
z = y / 2
else:
z = y * 2
zlist.append(z)
Now if I want to plot z for all the x between (0, 0.3), I presumably would need some marker on each element in zlist indicating its inputs variables. How would I attach such marker and then access it from the list when plotting?
I don't actually know anything about Numpy, so someone please comment and tell me if I'm making a fool out of myself. It seems like vanilla python behavior, though.
Rather than appending z, let's append (z,x) instead. Now zlist is a list of tuples, and you can loop through and plot by checking zlist[i][1].
zlist = []
for _ in range(100):
x = np.random.random()*1.
y = np.random.random()*.5
if x < .5:
z = y / 2
else:
z = y * 2
zlist.append((z,x))
for value in zlist:
if value[1] > 0 and value[1] < 0.3:
# Plot value[0]
# Or if you prefer list comprehensions:
# [value[0] for value in zlist if value[1] >0 and value[1] < 0.3]
# that will return a list with only the z values in zlist.
With numpy it's almost always much more efficient to perform operations on vectors and
arrays rather than on built-in Python sequence types such as lists. Here's one
way you can quickly find F(x, y) for every combination of two sets of random x
and y values without looping in Python. The result is going to be an nx-by-ny
array Z, where Z[i, j] = F(x[i], y[j]).
First of all, you can generate all of your x, y inputs as vectors:
nx = 100
ny = 200
x = np.random.random(size=nx) * 1.
y = np.random.random(size=ny) * 5.
For the result to be an nx-by-ny array, you could take these two vectors and
multiply them by ones to get two 2D nx-by-ny arrays containing the x and y
values in the rows and columns respectively. You can do this by taking advantage of numpy's
broadcasting rules:
x_arr = x[:,np.newaxis] * np.ones((nx,ny))
y_arr = y[np.newaxis,:] * np.ones((nx,ny))
The function you will apply to each x,y pair depends on the x value.
Fortunately, you can use np.where(<condition>, <do_this>, <do_that>) to apply
different operations to the values in your input depending on some condition:
Z = np.where(x_arr < 0.5, y_arr / 2., y_arr * 2.)
We can check that all the results are correct:
for i in xrange(nx):
for j in xrange(ny):
if x[i] < 0.5:
assert Z[i, j] == y[j] / 2.
else:
assert Z[i, j] == y[j] * 2
There's actually an even cleaner way to compute Z without expanding x and y into 2D arrays. Using the same broadcasting trick we used to get
x_arr and y_arr, you can pass x and y directly to np.where():
x2 = x[:,np.newaxis]
y2 = y[np.newaxis,:]
Z2 = np.where(x2 < 0.5, y2 / 2., y2 * 2.)
assert np.all(Z == Z2)

Categories

Resources