Get angle into range 0 - 2*pi - python - python

In my simulation i compute multiple values for a phase, for example
phi = np.linspace(-N,N,1000)
where N can be large.
Is there an easy way to map the values to the intervall [0,2pi) ?

Does that work ?
import numpy as np
import math
N=10
phi = np.linspace(-N,N,1000)
phi = phi%(2*math.pi)
print(phi)
Output
[2.56637061 2.58639063 ... 3.69679467 3.71681469]

It sounds like you are looking for np.interp. Scipy offers an interpolate function too.
For a usage example, to map the values of phi (which are between -N and N) to [0, 2π] try
np.interp(phi, (-N, N), (0, 2*np.pi))
To exclude 2π you could either change upper bound so no value maps onto 2π.
np.interp(phi, (-N, N + 1), (0, 2*np.pi))
Or reduce the largest value you include in phi
phi = np.linspace(-N, N, 1000, endpoint=False)
I believe it would be easier to just ask for the values directly.
For example, 1000 points over the range [0, 2π] can be given by
np.linspace(0, 2*np.pi, 1000)
And for the range [0, 2π) which excludes the value 2π
np.linspace(0, 2*np.pi, 1000, endpoint=False)

Another possible way:
First, convert to the [-pi, pi] interval using np.arctan2(np.sin(angle), np.cos(angle)). Then, you still need to transform the negative values. A final function like this would work:
def convert_angle_to_0_2pi_interval(angle):
new_angle = np.arctan2(np.sin(angle), np.cos(angle))
if new_angle < 0:
new_angle = abs(new_angle) + 2 * (np.pi - abs(new_angle))
return new_angle
To confirm, run:
angles = [10, 200, 365, -10, -180]
print(np.rad2deg([convert_angle_to_0_2pi_interval(np.deg2rad(a)) for a in angles]))
...which prints: [ 10., 200., 5., 350., 180.]

Related

Returning r at different theta values with numpy

I need to generate a table based on what r equals at different theta values.
I am easily able to graph and show the equation with matplotlib, and was hoping that there was an easy way to:
give numpy the theta variable, my curve equation, and viola, return the r value
I tried to look at the documentation of numpy but am having a hard time finding what I need.
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
mpl.style.use('default')
# Number of Points Ploted
# Change this numer to affect accuracy of the graph
n = 3000
theta = np.linspace(0, 2.0*np.pi, n)
def show_grid():
plt.grid(True)
plt.legend()
plt.show()
# Setting the range of theta to [0, 2π] for this specific equation
theta4 = np.linspace(0, 2*np.pi, n)
# Writing the equation
curve4 = 5*np.cos(64*theta)
ax1 = plt.subplot(111, polar=True)
ax1.plot(theta4, curve4, color='xkcd:cyan', label='CURVE 4: r = 5cos(64θ), [0, 2π)')
ax1.set_ylim(0,5)
ax1.set_yticks(np.linspace(0,5,6))
show_grid()
The above code produces a graph nicely, but:
Can I use the same variables to return r at theta?
It is in general not guaranteed that the array of theta values actually contains the value you want to query. As an example consider
theta = np.array([1,2,3,4])
r = np.array([8,7,6,5])
Now you want to know the value of r at theta0 = 2.5, but since that value is not part of theta it has no corresponding value in r.
So you may decide to find the value of r at the theta that comes after theta0, in this case 3 is the next value in theta after 2.5, so you might be looking for r == 6,
theta0 = 2.5
print(r[np.searchsorted(theta, theta0)]) # prints 6
Or you may want to interpolate the r values on theta, in this case 2.5 is halfway between 2 and 3, so you are looking for 6.5 which is halfway between 7 and 6,
theta0 = 2.5
print(np.interp(theta0, theta, r)) # prints 6.5
Or more generally, you have an actual function, which defines r(theta). Here,
theta = np.array([1,2,3,4])
rf = lambda x: -x + 9
r = rf(theta)
print(r) # prints [8,7,6,5]
print(rf(theta0)) # prints 6.5
The last case for your example would look like
theta = np.linspace(0, 2*np.pi, 3001)
# Writing the equation
r = lambda theta: 5*np.cos(64*theta)
ax1 = plt.subplot(111, polar=True)
ax1.plot(theta, r(theta), label='CURVE 4: r = 5cos(64θ), [0, 2π)')
print(r(np.pi/2)) # prints 5
plt.show()

Matplotlib plotting in wrong order

Basically I have two arrays, one containing the values of the x-axis and the second containing the values of the y-axis. The problem is, when I do
plt.semilogy(out_samp,error_mc)
I get this
Which doesn't make any sense. That is because the plot functions plots everything as it encounters in the x array, not caring whether it's sorted in ascending order or not. How can I sort these two arrays so that the x array is sorted by increasing value and the y axis sorted in the same way so that the points are the same but the plot is connected so that it doesn't make this mess?
It is easier to zip, sort and unzip the two lists of data.
Example:
xs = [...]
ys = [...]
xs, ys = zip(*sorted(zip(xs, ys)))
plot(xs, ys)
See the zip documentation here: https://docs.python.org/3.5/library/functions.html#zip
Sort by the value of x-axis before plotting. Here is an MWE.
import itertools
x = [3, 5, 6, 1, 2]
y = [6, 7, 8, 9, 10]
lists = sorted(itertools.izip(*[x, y]))
new_x, new_y = list(itertools.izip(*lists))
# import operator
# new_x = map(operator.itemgetter(0), lists) # [1, 2, 3, 5, 6]
# new_y = map(operator.itemgetter(1), lists) # [9, 10, 6, 7, 8]
# Plot
import matplotlib.pylab as plt
plt.plot(new_x, new_y)
plt.show()
For small data, zip (as mentioned by other answerers) is enough.
new_x, new_y = zip(*sorted(zip(x, y)))
The result,
An alternative to sort the lists would be to use NumPy arrays and use np.sort() for sorting. The advantage with using arrays would be a vectorized operation while computing a function like y=f(x). Following is an example of plotting a normal distribution:
Without using sorted data
mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)
Output 1
With using np.sort() This allows straightforwardly using sorted array x while computing the normal distribution.
mu, sigma = 0, 0.1
x = np.sort(np.random.normal(mu, sigma, 200))
# or use x = np.random.normal(mu, sigma, 200).sort()
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)
Alternatively if you already have both x and y data unsorted, you may use numpy.argsort to sort them a posteriori
mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(np.sort(x), f[np.argsort(x)], '-bo', ms = 2)
Notice that the code above uses sort() twice: first with np.sort(x) and then with f[np.argsort(x)]. The total sort() invocations can be reduced to one:
# once you have your x and f...
indices = np.argsort(x)
plt.plot(x[indices], f[indices], '-bo', ms = 2)
In both cases the output is
Output 2
just do this
list=zip(*sorted(zip(*(x,y))))
plt.plot(*list)
sorted function will sort according to the 1st argument i.e x values
I think you need to sort one array and the other array should also get sorted based on the first array. I got this solution from some other stack overflow question. Most probably this should be your solution.
out_samp,error_mc=zip(*sorted(zip(out_samp,error_mc)))
Now plot those two values, you get a correct graph.
You can convert your arrays to numpy arrays, then use argsort on the first array, take the the array and sort both arrays with the argsort array.

Specify the shift for numpy.correlate

I wonder if there is a possibility to specify the shift expressed by k variable for the cross-correlation of two 1D arrays. Because with the numpy.correlate function and its mode parameter set to 'full' I will get cross-correlate coefficients for each k shift for whole length of the taken array (assuming that both arrays are the same size). Let me show you what I mean exactly on below example:
import numpy as np
# Define signal 1.
signal_1 = np.array([1, 2 ,3])
# Define signal 2.
signal_2 = np.array([1, 2, 3])
# Other definitions.
Xi = signal_1
Yi = signal_2
N = np.size(Xi)
k = 3
Xs = np.average(Xi)
Ys = np.average(Yi)
# Cross-covariance coefficient function.
def crossCovariance(Xi, Yi, N, k, Xs, Ys, forCorrelation = False):
autoCov = 0
for i in np.arange(0, N-k):
autoCov += ((Xi[i+k])-Xs)*(Yi[i]-Ys)
if forCorrelation == True:
return autoCov/N
else:
return (1/(N-1))*autoCov
# Expected value function.
def E(X, P):
expectedValue = 0
for i in np.arange(0, np.size(X)):
expectedValue += X[i] * (P[i] / np.size(X))
return expectedValue
# Cross-correlation coefficient function.
def crossCorrelation(Xi, Yi, k):
# Calculate the covariance coefficient.
cov = crossCovariance(Xi, Yi, N, k, Xs, Ys, forCorrelation = True)
# Calculate standard deviations.
EX = E(Xi, np.ones(np.size(Xi)))
SDX = (E((Xi - EX) ** 2, np.ones(np.size(Xi)))) ** (1/2)
EY = E(Yi, np.ones(np.size(Yi)))
SDY = (E((Yi - EY) ** 2, np.ones(np.size(Yi)))) ** (1/2)
# Calculate correlation coefficient.
return cov / (SDX * SDY)
# Express cross-covariance or cross-correlation function in a form of a 1D vector.
def array(k, norm = True):
# If norm = True, return array of autocorrelation coefficients.
# If norm = False, return array of autocovariance coefficients.
vector = np.array([])
shifts = np.abs(np.arange(-k, k+1, 1))
for i in shifts:
if norm == True:
vector = np.append(crossCorrelation(Xi, Yi, i), vector)
else:
vector = np.append(crossCovariance(Xi, Yi, N, i, Xs, Ys), vector)
return vector
In my example, calling the method array(k, norm = True) for different values of k will give resuslt as I shown below:
k = 3, [ 0. -0.5 0. 1. 0. -0.5 0. ]
k = 2, [-0.5 0. 1. 0. -0.5]
k = 1, [ 0. 1. 0.]
k = 0, [ 1.]
My approach is good for the learning purposes but I need to move to the native numpy functions in order to speed up my analysis. How one could specify the k shift value while using the native numpy.correlate function? PS k parameter specify the "time" shift between two arrays. Thank you in advance.
Whilst I'm not aware of any built-in function for computing the cross-correlation for a particular range of signal lags, you can speed your version up a lot by vectorization, i.e. performing operations on arrays rather than single elements in an array.
This version uses only a single Python loop over the lags:
import numpy as np
def xcorr(x, y, k, normalize=True):
n = x.shape[0]
# initialize the output array
out = np.empty((2 * k) + 1, dtype=np.double)
lags = np.arange(-k, k + 1)
# pre-compute E(x), E(y)
mu_x = x.mean()
mu_y = y.mean()
# loop over lags
for ii, lag in enumerate(lags):
# use slice indexing to get 'shifted' views of the two input signals
if lag < 0:
xi = x[:lag]
yi = y[-lag:]
elif lag > 0:
xi = x[:-lag]
yi = y[lag:]
else:
xi = x
yi = y
# x - mu_x; y - mu_y
xdiff = xi - mu_x
ydiff = yi - mu_y
# E[(x - mu_x) * (y - mu_y)]
out[ii] = xdiff.dot(ydiff) / n
# NB: xdiff.dot(ydiff) == (xdiff * ydiff).sum()
if normalize:
# E[(x - mu_x) * (y - mu_y)] / (sigma_x * sigma_y)
out /= np.std(x) * np.std(y)
return lags, out
Some more general points of advice:
As I mentioned in the comments, you should try to give your functions names that are informative, and that aren't likely to conflict with other things in your namespace (e.g. array vs np.array).
It's much better to make your functions self-contained. In your version, N, k, Xs and Ys are defined outside the main function. In this situation you might accidentally modify or overwrite one of these variables, and it can get tricky to debug errors caused by this sort of thing.
Appending to numpy arrays (e.g. using np.append or np.concatenate) is slow, so avoid it whenever you can. If, as in this case, you know the size of the output ahead of time, it's much faster to pre-allocate the output array (e.g. using np.empty or np.zeros), then fill in the elements. If you absolutely have to do concatenation, it's often faster to append to a normal Python list, then convert it to a numpy array at the end.
It's available by specifying maxlags:
import matplotlib.pyplot as plt
xcorr = plt.xcorr(signal_1, signal_2, maxlags=1)
Documentation can be found here. This implementation is based on np.correlate.

Summing one array in terms of another - python

I have two corresponding 2D arrays, one of velocity, one of intensity. The values of intensity match each of the velocity elements.
I have created another 1d array that that goes from min to max velocity in even bin widths.
How would I sum the intensity values from my 2d array which correspond to my velocity bins in my 1d array.
For example: if I have I = 5 corresponding to velocity = 101km/s, then this is added to the bin 100 - 105 km/s.
Here's my input:
rad = np.linspace(0, 3, 100) # polar coordinates
phi = np.linspace(0, np.pi, 100)
r, theta = np.meshgrid(rad, phi) # 2d arrays of r and theta coordinates
V0 = 225 # Velocity function w/ constants.
rpe = 0.149
alpha = 0.003
Vr = V0 * (1 - np.exp(-r / rpe)) * (1 + (alpha * np.abs(r) / rpe)) # returns 100x100 array of Velocities.
Vlos = Vr * np.cos(theta)# Line of sight velocity assuming the observer is in the plane of the polar disk.
a = (r**2) # intensity as a function of radius
b = (r**2 / 0.23)
I = (3.* np.exp(-1. * a)) - (1.8 * np.exp(-1. * b))
I wish to first create velocity bins from Vmin to Vmax and then sum the intensities over each bin.
My desired out put would be something along the lines of
V_bins = [0, 5, 10,... Vlos.max()]
I_sum = [1.4, 1.1, 1.8, ... 1.2]
plot(V_bins, I_sum)
EDIT: I have come up with temporary solution but perhaps there is a more elegant/efficient method of achieving it?
The two array Vlos and I are both 100 by 100 matrices.
Vlos = array([[ 0., 8.9, 17.44, ..., 238.5],...,
[-0., -8.9, -17.44, ..., -238.5]])
I = random.random((100, 100))
V = np.arange(Vlos.min(), Vlos.max()+5, 5)
bins = np.zeros(len(V))
for i in range(0, len(V)-1):
for j in range(0, len(Vlos)): # horizontal coordinate in matrix
for k in range(0, len(Vlos[0])): # vert coordinate
if Vlos[j,k] >= V[i]and Vlos[j,k] < V[i+1]:
bins[i] = bins[i] + I[j,k]
The result is plotted below.
The overall shape in the histogram is to be expected, however I don't understand the spike in the curve at V = 0. As far as I can tell this isn't there in the data which leads me to question my method.
Any further help would be appreciated.
import numpy as np
bins = np.arange(100,120,5)
velocities = np.array([101, 111, 102, 112])
intensities = np.array([1,2,3,4])
h = np.histogram(velocities, bins, weights=intensities)
print h
Output:
(array([4, 0, 6]), array([100, 105, 110, 115]))

How to generate 2D gaussian with Python?

I can generate Gaussian data with random.gauss(mu, sigma) function, but how can I generate 2D gaussian? Is there any function like that?
If you can use numpy, there is numpy.random.multivariate_normal(mean, cov[, size]).
For example, to get 10,000 2D samples:
np.random.multivariate_normal(mean, cov, 10000)
where mean.shape==(2,) and cov.shape==(2,2).
I'd like to add an approximation using exponential functions. This directly generates a 2d matrix which contains a movable, symmetric 2d gaussian.
I should note that I found this code on the scipy mailing list archives and modified it a little.
import numpy as np
def makeGaussian(size, fwhm = 3, center=None):
""" Make a square gaussian kernel.
size is the length of a side of the square
fwhm is full-width-half-maximum, which
can be thought of as an effective radius.
"""
x = np.arange(0, size, 1, float)
y = x[:,np.newaxis]
if center is None:
x0 = y0 = size // 2
else:
x0 = center[0]
y0 = center[1]
return np.exp(-4*np.log(2) * ((x-x0)**2 + (y-y0)**2) / fwhm**2)
For reference and enhancements, it is hosted as a gist here. Pull requests welcome!
Since the standard 2D Gaussian distribution is just the product of two 1D Gaussian distribution, if there are no correlation between the two axes (i.e. the covariant matrix is diagonal), just call random.gauss twice.
def gauss_2d(mu, sigma):
x = random.gauss(mu, sigma)
y = random.gauss(mu, sigma)
return (x, y)
import numpy as np
# define normalized 2D gaussian
def gaus2d(x=0, y=0, mx=0, my=0, sx=1, sy=1):
return 1. / (2. * np.pi * sx * sy) * np.exp(-((x - mx)**2. / (2. * sx**2.) + (y - my)**2. / (2. * sy**2.)))
x = np.linspace(-5, 5)
y = np.linspace(-5, 5)
x, y = np.meshgrid(x, y) # get 2D variables instead of 1D
z = gaus2d(x, y)
Straightforward implementation and example of the 2D Gaussian function. Here sx and sy are the spreads in x and y direction, mx and my are the center coordinates.
Numpy has a function to do this. It is documented here. Additionally to the method proposed above it allows to draw samples with arbitrary covariance.
Here is a small example, assuming ipython -pylab is started:
samples = multivariate_normal([-0.5, -0.5], [[1, 0],[0, 1]], 1000)
plot(samples[:, 0], samples[:, 1], '.')
samples = multivariate_normal([0.5, 0.5], [[0.1, 0.5],[0.5, 0.6]], 1000)
plot(samples[:, 0], samples[:, 1], '.')
In case someone find this thread and is looking for somethinga little more versatile (like I did), I have modified the code from #giessel. The code below will allow for asymmetry and rotation.
import numpy as np
def makeGaussian2(x_center=0, y_center=0, theta=0, sigma_x = 10, sigma_y=10, x_size=640, y_size=480):
# x_center and y_center will be the center of the gaussian, theta will be the rotation angle
# sigma_x and sigma_y will be the stdevs in the x and y axis before rotation
# x_size and y_size give the size of the frame
theta = 2*np.pi*theta/360
x = np.arange(0,x_size, 1, float)
y = np.arange(0,y_size, 1, float)
y = y[:,np.newaxis]
sx = sigma_x
sy = sigma_y
x0 = x_center
y0 = y_center
# rotation
a=np.cos(theta)*x -np.sin(theta)*y
b=np.sin(theta)*x +np.cos(theta)*y
a0=np.cos(theta)*x0 -np.sin(theta)*y0
b0=np.sin(theta)*x0 +np.cos(theta)*y0
return np.exp(-(((a-a0)**2)/(2*(sx**2)) + ((b-b0)**2) /(2*(sy**2))))
We can try just using the numpy method np.random.normal to generate a 2D gaussian distribution.
The sample code is np.random.normal(mean, sigma, (num_samples, 2)).
A sample run by taking mean = 0 and sigma 20 is shown below :
np.random.normal(0, 20, (10,2))
>>array([[ 11.62158316, 3.30702215],
[-18.49936277, -11.23592946],
[ -7.54555371, 14.42238838],
[-14.61531423, -9.2881661 ],
[-30.36890026, -6.2562164 ],
[-27.77763286, -23.56723819],
[-18.18876597, 41.83504042],
[-23.62068377, 21.10615509],
[ 15.48830184, -15.42140269],
[ 19.91510876, 26.88563983]])
Hence we got 10 samples in a 2d array with mean = 0 and sigma = 20

Categories

Resources