Calling a function containing an array of x values - arrays

I want to call a function in a program, that has the same format as the following, but where the x values are in the form of an array of shape = (426, 240). Can someone help with this?
The function is:
def f(x):
if x < 0:
return -2*x
else :
return -x
x = np.arange(-100, 100, 1)
plt.plot(x, list(map(f, x)), 'b-') # for python3
#plt.show()
The part of the code that calls the function would look like this:
def nucleation_and_motion_in_G_gradient_fluid_2D(writer, args, R=60):
dx = 2*R / args.height
x = (np.arange(args.width) - args.width // 2) * dx
y = (np.arange(args.height) - args.height // 2) * dx
x, y = np.meshgrid(x, y, indexing='ij')
def source_G(t):
center = np.exp(-0.5*(t-5)**2) * 10
gradient = (1+np.tanh(t-30)) * 0.0003
piecewise_1 = f(x) # ***function f(x) called here***
return -(
np.exp(-0.5*(x*x + y*y)) #+ np.exp(-0.5*((x)**2 + y*y))
) * center + piecewise_1 * gradient # piecewise function test
Main code here.
I already know the code works for a trapezoid function in combination with the x array, as follows:
(code requires: from scipy import signal)
def trapezoid_signal(x, width=2., slope=1., amp=10., offs=1):
a = slope * width * signal.sawtooth(2 * np.pi * 1/10 * x/width - 0.8, width=0.5)/4.
a[a>amp/2.] = amp/2.
a[a<-amp/2.] = -amp/2.
return a + amp/2. + offs
def source_G(t):
center = np.exp(-0.5*(t-5)**2) * 10
gradient = (1+np.tanh(t-30)) * 0.0003
trapezoid = trapezoid_signal(x, width=40, slope=5, amp=50)
return -(
np.exp(-0.5*(x**2 + y**2))
) * center + trapezoid * gradient # one soliton particle in 2 dimensions of xy with z axis as concentration potential

If you want to make this
def f(x):
if x < 0:
return -2*x
else :
return -x
compatible with vectorization, you can use the following (very common) trick:
def f(x):
neg = x < 0
return neg * (-2 * x) + (1 - neg) * -x
It works!
>>> f(np.arange(-5, 5))
array([10, 8, 6, 4, 2, 0, -1, -2, -3, -4])

Related

Appending 2D array to a list of arrays

My code has a problem. I know what the problem is.
I cant append an array to another array with the append method.
I need to find something else. What is an effective and not complicated way to append an array to an array?
This code should plot the trajectory of a ball that is fired from different angles ( 5 to 85 degrees).
import numpy as np
import matplotlib.pyplot as plt
alpha = np.arange(5,86,5)
v0 = 30
Cd = 1.2
A = 0.02
M = 1.5
gvec = np.array([0,-9.813])
rho = 1.225
dt = 0.01
for a in alpha:
xvec = np.array([0.0,0.0])
vvec = v0 * np.array([np.cos(a),np.sin(a)])
xall = []
while xvec[1] > 0:
V = np.sqrt(np.sum(vvec*vvec))
Dvec = -0.5 * rho * Cd * A * V**2 * vvec /V
accvec = gvec + Dvec/M
vvec = vvec + accvec*dt
xvec = xvec + vvec*dt
xall.append(xvec)
xall = np.array(xall)
plt.plot(xall[:,0] ,xall[:,1])
plt.show()
I would like to create an array " xall" in the following format.
xall are all the coordinates. so this is what i want.
xall = array([x1,y1], [x2,y2], ....... , [xn, yn])
Your code is ok, but the condition of while is somehow wrong.
xvec = np.array([0.0,0.0])
vvec = v0 * np.array([np.cos(a),np.sin(a)])
xall = []
while xvec[1] > 0:
Since you define xvec as many 0's array, the condition for while is not met and just passed. Once you include xvec[1] = 0, you can obtain a plot.
Btw, the sin and cos function treats the angle as radian, so you have to modify a bit
vvec = v0 * np.array([np.cos(np.pi * a / 180), np.sin(np.pi * a / 180)])
and the result will be:

How can i concatenate three 2D arrays which contain hue, saturation and intensity values in their respective arrays and display that as an image?

I am new to image processing and python. As you can see from my code, i managed to convert my RGB image to HSI by using the different formulas that i found.
I stored the values of hue, saturation and intensity in three different arrays. That is also in the code down below. How can i concatenate those three arrays and display the concatenated image as an image?
import math
from PIL import Image
img = Image.open("D:\\Texture analysis\\trees-clolorful-aerial-view-wallpaper.jpg")
rgb_img = img.convert('RGB')
row, col = img.size
print(row, col)
i = j = 0
satValue = 0
inValue = 0
hueValue = 0
squareValue = 0
hueArray = [[0 for x in range(row)] for y in range(col)]
satArray = [[0 for x in range(row)] for y in range(col)]
inArray = [[0 for x in range(row)] for y in range(col)]
division = 0
denominator = 0
numerator = 0
radAngle = 0
degAngle = 0
product = 0
sqr = 0
count = 0
uCount = 0
while i < row:
j = 0
while j < col:
red, green, blue = rgb_img.getpixel((i, j))
hRed = sRed = iRed = red
hGreen = sGreen = iGreen = green
hBlue = sBlue = iBlue = blue
# =========================Saturation Calculation==============================
if sRed == 0 and sGreen == 0 and sBlue == 0:
satValue = 0
satArray[i][j] = 0
else:
if (sRed < sGreen) and (sRed < sBlue):
satValue = 1 - (((3) * (sRed)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
elif (sGreen < sRed) and (sGreen < sBlue):
satValue = 1 - (((3) * (sGreen)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
else:
satValue = 1 - (((3) * (sBlue)) / (sRed + sGreen + sBlue))
satArray[i][j] = satValue
# print(satValue)
# =============================================================================
# ==========================Intensity Calculation==============================
inValue = (iRed + iGreen + iBlue) / 3
inArray[i][j] = inValue
count += 1
print(inValue, count)
# =============================================================================
# =============================Hue Calculation=================================
product = (hRed - hBlue) * (hGreen - hBlue)
sqr = (hRed - hGreen) * (hRed - hGreen)
denominator = math.sqrt(sqr + product)
if denominator != 0:
numerator = ((hRed - hGreen) + (hRed - hBlue)) / 2
division = numerator / denominator
radAngle = math.acos(division)
degAngle = math.degrees(radAngle)
if hBlue <= hGreen:
hueValue = degAngle
hueArray[i][j] = hueValue
elif hBlue > hGreen:
hueValue = 360 - degAngle
hueArray[i][j] = hueValue
elif denominator == 0:
hueValue = 0
hueArray[i][j] = hueValue
#print(hueValue, count)
# =============================================================================
j += 1
i += 1 print(i, j)
PS. You will be seeing a lot of my amateur code in the future as well :D
I can see what's going wrong now I am back at a computer. You probably tried this:
#!/usr/bin/env python3
from PIL import Image
img = Image.open('start.png')
hsvimg = img.convert('HSV')
hsvimg.save('result.png')
And if you do that, you actually get an error message:
OSError: cannot write mode HSV as PNG
because, PNG images are always in sRGB colourspace, so it correctly declines to write your HSV image. The thing is though, that the colourspace conversion actually worked and the values in the image actually are the HSV values that you want. You can check this with:
img.getpixel((X,Y))
and
hsvimg.getpixel((X,Y))
where X and Y are any random coordinates you like. You will see the the latter is always the correct HSV representation of the former's RGB colour.
I am not sure what you are trying to do overall, so I can't really advise properly, but one thing you could do is "lie through your teeth" and tell PIL/Pillow that the image is RGB even though you know it is HSV. So if you do:
hsvimg = img.convert('HSV')
hsvimg.mode='RGB' # Tell PIL image is RGB
hsvimg.save('result.png')
it will save an image but it, and all other viewers, will show your Hue as Blue, your Saturation as Green and your Value as Blue.
I am guessing you have other processing to do, and this is only an intermediate aspect of your processing, so it probably won't matter and you can probably carry on and do your processing and convert back at the end and save to an sRGB PNG file without needing to lie.
In answer to your actual question, you can split and merge channels like this with PIL/Pillow:
# Split and recombine with PIL
r,g,b = img.split()
merged = Image.merge(mode='RGB',bands=(r,g,b)))
Or, if you prefer Numpy which is often faster:
# Open image as Numpy array
img = np.array(Image.open('start.png'))
# Split into 3 channels/arrays/bands
r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]
# Recombine to single image
merged = np.dstack((r, g, b))

Counting points in an array that meet certain conditions

I am having trouble getting my code to count the correct number of elements from three different arrays, with each array having its own parameter. I would like the element to be counted if its meets all three parameters this is what I have so far
import numpy as np
import random as rand
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
n = 10
x0 = np.zeros(n)
y0 = np.zeros(n)
z0 = np.zeros(n)
x1 = np.zeros(n)
y1 = np.zeros(n)
z1 = np.zeros(n)
hit = 0
for k in range (n):
theta = rand.uniform(0.0, np.pi)
phi = rand.uniform(0, (2 * np.pi))
x0[k] = np.sin(phi) * np.cos(theta)
y0[k] = np.sin(phi) * np.sin(theta)
z0[k] = np.cos(theta)
for j in range (n):
theta = rand.uniform(0.0, np.pi)
phi = rand.uniform(0, (2 * np.pi))
x1[j] = np.sin(phi) * np.cos(theta)
y1[j] = np.sin(phi) * np.sin(theta)
z1[j] = np.cos(theta)
for i in range(n):
if np.any(x1[j] > -0.3) and np.any(x1[j] < 0.7) and np.any(y1[j] > -0.3) and np.any(y1[j] <0.7) and np.any(z1[j] > -0.3) and np.any(z1[j] < 0.3):
hit += 1
ax.plot_wireframe([x0[k],x1[j]],[y0[k],y1[j]],[z0[k],z1[j]])
print (hit)
print (x1,y1,z1)
plt.show()
I would like for only the end points to be counted if they meet the three parameters.
Thank you

Obtaining approximate derivatives with variable x spacing in MATLAB? [duplicate]

This question already has answers here:
Numerical derivative of a vector
(3 answers)
Closed 7 years ago.
I have two arrays: x and y. In practice, y is dependent on x, but both arrays are measured values. I would like to obtain the derivative of y with respect to x. If x were uniformly spaced (i.e. x=[1 2 3 4 5]), I could do something with diff like this:
h = 0.001;
x = -pi:h:pi;
f = sin(X);
y = diff(f)/h;
However, x is not uniformly spaced (i.e. x=[1 1.9 2.8 4.1]). How can I obtain the partial derivative of this data set?
A good way to do it is gradient,
dydx = gradient(y, x);
I like it because it returns a vector which is the same length as x and y. The downside though, is it's first order accurate. This can sometimes be a problem, a fix could be to write your own,
x = unique([linspace(0, 2*pi, 50), logspace(0, log10(2*pi), 50)]);
y = cos(x) ;
subplot(2,1,1) ;
plot(x, Gradient(y, x), x, gradient(y,x), x, -sin(x));
legend('2^{nd} order', '1^{st} order', 'exact') ;
subplot(2,1,2) ;
plot(x, Gradient(y, x) + sin(x), x, gradient(y,x) + sin(x));
legend('2^{nd} order - exact', '1^{st} order - exact')
With Gradient being
function dydx = Gradient(y,x)
y = y(:);
p = x(3:end) - x(2:end-1);
p = p(:);
m = x(2:end-1) - x(1:end-2);
m = m(:);
p1 = x(2) - x(1);
p2 = x(3) - x(1);
m1 = x(end) - x(end-1);
m2 = x(end) - x(end-2);
dydx = reshape([ ((-p1^2 + p2^2)*y(1) - p2^2*y(2) + p1^2*y(3))/(p1*(p1 - p2)*p2);
((-m.^2 + p.^2).*y(2:end-1) - p.^2.*y(1:end-2) + m.^2.*y(3:end))./(m.*p.*(m + p));
((m1^2 - m2^2)*y(end) + m2^2*y(end-1) - m1^2*y(end-2))/(m1^2*m2 - m1*m2^2) ...
], size(x));
end
Edit:
Improved it for multidimensional array and constant spacing support
function dydx = Gradient(y,x)
if length(y) < 3
dydx = gradient(y,x);
return
end
[~, n] = max(size(y));
N = ndims(y);
i = repmat({':'},1,N-1);
y = permute(y, [n, 1:n-1, n+1:N]);
if isscalar(x)
%"x" is actually a spacing value
p = x;
m = x;
p1 = x;
p2 = x;
m1 = x;
m2 = x;
else
if isvector(x)
x = repmat(x(:), size(y(1, i{:})));
else
x = permute(x, [n, 1:n-1, n+1:N]);
end
if all(size(x) ~= size(y))
error('Sizes of arrays must be the same.')
end
p = x(3:end, i{:}) - x(2:end-1, i{:});
m = x(2:end-1, i{:}) - x(1:end-2, i{:});
p1 = x(2, i{:}) - x(1, i{:});
p2 = x(3, i{:}) - x(1, i{:});
m1 = x(end, i{:}) - x(end-1, i{:});
m2 = x(end, i{:}) - x(end-2, i{:});
end
dydx = ipermute([ ((-p1.^2 + p2.^2).*y(1,i{:}) - p2.^2.*y(2,i{:}) + p1.^2.*y(3,i{:}))./(p1.*(p1 - p2).*p2);
((-m.^2 + p.^2).*y(2:end-1,i{:}) - p.^2.*y(1:end-2,i{:}) + m.^2.*y(3:end,i{:}))./(m.*p.*(m + p));
((m1.^2 - m2.^2).*y(end,i{:}) + m2.^2.*y(end-1,i{:}) - m1.^2.*y(end-2,i{:}))./(m1.^2.*m2 - m1.*m2.^2) ...
], [n, 1:n-1, n+1:N]);
end

Passing Arrays as a parameter to a VBA function

I have a user defined Excell worksheet function (Linear) that interpolates from an array of X and an array of Y values at a defined X1 value, which works fine. I have tried to use this within another function (NPL in the example code below) be setting it a a Private Static function within a VBA module and then calling the function using arrays of data created within the function.
When I use this in the spreadsheet I get a #VALUE error.
Any ideas what I am doing wrong?
Example code:
Function NPL(Length, Beam)
A = Array(1, 2, 3, 4)
B = Array(2, 4, 6, 8)
C = Linear(A, B, 1.5)
NPL = C
End Function
Private Static Function Linear(X, Y, X1)
N = 0
I = 1
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
A = 0
I = 0
Do
I = I + 1
Loop Until X(I) > X1 Or I > N - 1
If X1 < X(N) And X1 > X(1) Then
Linear = Y(I - 1) + (X1 - X(I - 1)) * (Y(I) - Y(I - 1)) / (X(I) - X(I - 1))
ElseIf X1 > X(N) Or X1 = X(N) Then
Linear = Y(N)
Else
Linear = Y(1)
End If
End Function
Replace your
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
with
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = UBound(X) - LBound(X) + 1
This should work for any 1D array.

Resources