Fourier Transformation of 2D Matrix in Python - python

So, I have a matrix with 72x72 values, each corresponding to some energy on a triangular lattice with 72x72 sites. I'm trying to Fourier transform the values, but I'm not understanding how to do that with np.fft.fftn .
To illustrate my problem I have written the following basic code with some random values. The triangular gives the lattice x,y coordinates.
import numpy as np
import matplotlib.pyplot as plt
def triangular(nsize):
x=0
y=0
X=np.zeros((nsize,nsize))
Y=np.zeros((nsize,nsize))
for i in range(nsize):
for j in range(nsize):
X[i,j]+=1/2*j+i
Y[i,j]+=np.sqrt(3)/2*j
return(X,Y)
xx = triangular(72)[0]
yy = triangular(72)[1]
plt.figure()
plt.pcolormesh(xx, yy, np.reshape(np.random.rand(72**2),(72,72)))
I'm not using random data, but I wanted not to make the example that complicated. In fact I see everytime the same plot, when I now use the following FFT:
matrix = []
matrix.append(triangular(72)[0])
matrix.append(triangular(72)[1])
matrix.append(np.reshape(np.random.rand(72**2),(72,72)))
spectrum_3d = np.fft.fftn(matrix) # Fourrier transform along x, y, energy
kx = np.linspace(-4*np.pi/3,4*np.pi/3,72) #this is the range I want to plot
ky = np.linspace(-2*np.pi/np.sqrt(3),2*np.pi/np.sqrt(3),72)
Ky, Kx = np.meshgrid(ky, kx, indexing='ij') #making a grid
plt.figure(figsize=(11,9))
psd = plt.pcolormesh(Kx, Ky, abs(spectrum_3d[2])**2)
cbar = plt.colorbar(psd)
plt.xlabel('kx')
plt.ylabel('ky')
My result looks always the same and I don't know what went wrong. Also for my correlated values, which have a large symmetry the plot looks the same.

You can't 'see' the spectrum because of the DC dominance.
import numpy as np
import matplotlib.pyplot as p
%matplotlib inline
n=72
x=np.arange(n)
y=np.arange(n)
X,Y= np.meshgrid(x,y)
data=np.reshape(np.random.rand(n**2),(n,n))
data_wo_DC= data- np.mean(data)
spectrum = np.fft.fftshift(np.fft.fft2(data))
spectrum_wo_DC = np.fft.fftshift(np.fft.fft2(data_wo_DC))
freqx=np.fft.fftshift(np.fft.fftfreq(72,1)) #q(n, d=1.0)
freqy=np.fft.fftshift(np.fft.fftfreq(72,1))
fX,fY= np.meshgrid(freqx,freqy)
p.figure(figsize=(20,6))
p.subplot(131)
p.pcolormesh(X,Y, data)
p.colorbar()
p.subplot(132)
p.pcolormesh(fX,fY,np.abs(spectrum))
p.colorbar()
p.title('most data is in the DC')
p.subplot(133)
p.pcolormesh(fX,fY,np.abs(spectrum_wo_DC))
p.colorbar()
p.title('wo DC we can see the structure');

Related

operands could not be broadcast together with shapes (37,32,2) (2,2) getting pdf from Scipy Stats?

I have the code below, which is modeling the return and volatility of a stock using a bivariate Gaussian distribution. It keeps failing at the variable pdf, getting the error operands could not be broadcast together with shapes (37,32,2) (2,2) .
How would i go about fixing it?
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm
# Load data into a pandas dataframe
data = pd.read_csv('AAPL.csv')
# Calculate daily returns and volatility
returns = np.log(data['Close'] / data['Close'].shift(1))
volatility = returns.rolling(window=252).std() * np.sqrt(252)
# Stack the returns and volatility data into a single matrix
data = np.vstack([returns, volatility]).T
# Calculate mean and covariance
mean = np.mean(data, axis=0)
covariance = np.cov(data.T)
# Plot the data
plt.scatter(returns, volatility)
plt.xlabel('Returns')
plt.ylabel('Volatility')
# Generate a grid of x, y points
x, y = np.mgrid[returns.min():returns.max():0.01, volatility.min():volatility.max():0.01]
pos = np.dstack((x, y))
# Calculate the bivariate Gaussian distribution
rv = norm(mean,covariance)
pdf = rv.pdf(pos)
# Plot the bell-shaped curve
plt.contour(x, y, pdf, cmap='Blues')
plt.show()

What is the best way/method to digitize the data of a 3D surface into a grid of pixels with smaller resolution in Python?

I want to digitize (= average out over cells) photon count data into pixels given by a grid that tells how they are aligned. The photon count data is stored in a 2D array. I want to split that data into cells, each of which would correspond to a pixel. The idea is basically the same as changing an HD image to a smaller resolution. I'd like to achieve this in Python.
The digitizing function I've written:
import numpy as np
def digitize(function_data, grid_shape):
"""
function_data = 2D array of function values of some 3D shape,
eg.: exp(-(x^2 + y^2 -> want to digitize this
grid_shape: an array of length 2 which contains the dimensions of the smaller resolution
"""
l = len(function_data)
pixel_len_x = int(l/grid_shape[0])
pixel_len_y = int(l/grid_shape[1])
digitized_data = np.empty((grid_shape[0], grid_shape[1]))
for i in range(grid_shape[0]): #row-index of pixel in smaller-resolution grid
for j in range(grid_shape[1]): #column-index of pixel in smaller-resolution grid
hd_pixel = []
for k in range(pixel_len_y):
hd_pixel.append(z_data[k][j:j*pixel_len_x])
hd_pixel = np.ravel(hd_pixel) #turns 2D array into 1D to be able to compute average
pixel_avg = np.average(hd_pixel)
digitized_data[i][j] = pixel_avg
return digitized_data
In theory, this function should do what I want to achieve, but when tested it doesn't yield the expected results. Either a completed version of my function or any other method that achieves my goal would be extremely helpful.
You could also use a interpolation function, if you can use SciPy. Here we use one of the gridded data interpolating functions, RectBivariateSpline to upsample your function, but you can find numerous examples on this and other sites.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RectBivariateSpline as rbs
# Sampling coordinates
x = np.linspace(-2,2,20)
y = np.linspace(-2,2,30)
# Your function
f = np.exp(-(x[:,None]**2 + y**2))
# Interpolator
interp = rbs(x, y, f)
# Higher resolution coordinates
x_hd = np.linspace(x.min(), x.max(), x.size * 5)
y_hd = np.linspace(y.min(), y.max(), y.size * 5)
# New higher res function
f_hd = interp(x_hd, y_hd, grid = True)
# Some plots
fig, ax = plt.subplots(ncols = 2)
ax[0].imshow(f)
ax[1].imshow(f_hd)

Plot Distance matrix for a 1D array

I would like to plot a distance matrix plot for distance between 6 towns. A1 to A3 and B1 to B3.
I have calculated the distance like A1-B1, A1-B2....likewise....A3-B3 and I got an 1D array
I got a 1D numpy array for distance between 6 towns .
np.array(R)
[ 3.00 2.50 1.00 3.3192 2.383 2.7128 3.8662 3.6724 3.5112]
Now I want plot in an distance matrix format which should look something like as shown in Figure below.
it is just a representative data. I got lots of values so need python program.
Any suggestion or sample python matplotlib script will help.
Regards.
Looks like you got most of the way yourself. You can clean up your plot to make it a little more like what you intended by changing the axis labels to A1, A2,... and by printing the values of each cell within them.
The cleaned up version of your script is below:
import numpy as np
import matplotlib.pyplot as plt
R = np.array ([3.00, 2.50, 1.00, 3.3192, 2.383, 2.7128, 3.8662, 3.6724, 3.5112])
# Calculate the shape of the 2d array
n = int( np.sqrt( R.size ) )
C = R.reshape((n,n))
# Plot the matrix
plt.matshow(C,cmap="Reds")
ax = plt.gca()
# Set the plot labels
xlabels = ["B%d" % i for i in xrange(n+1)]
ylabels = ["A%d" % i for i in xrange(n+1)]
ax.set_xticklabels(xlabels)
ax.set_yticklabels(ylabels)
#Add text to the plot showing the values at that point
for i in xrange(n):
for j in xrange(n):
plt.text(j,i, C[i,j], horizontalalignment='center', verticalalignment='center')
plt.show()
And will create the following plot:
import numpy as np
from matplotlib.pylab import *
R = np.array ([3.00, 2.50, 1.00, 3.3192, 2.383, 2.7128, 3.8662, 3.6724, 3.5112])
C = np.split(R, 3)
print(C)
matshow(C,cmap=cm.gray)
plt.show()

Return the value of a 2D PDF given x and y in Python?

I have some data that I plotted the PDF using matplotlib's hist2D function.
The result looks like this:
The hist2d function returns a triple of arrays: H,xedges,yedges. H being the 2D histogram value.
Now I'd like to turn this discrete H matrix and turn it into a function, that returns the value of H for any given (x,y) input.
In other words I'd like to turn my 2D histogram into a 2D step function. Is there a specific function that would be computationally cheap that I could use on that purpose?
This looks like a pretty simple operation (usually done for image processing but with pixel indices instead of real numbers) but I'm unable to find anything about it, can you please help me?
You can construct an interpolator from the counts like this:
from numpy import random, histogram2d, diff
import matplotlib.pyplot as plt
from scipy.interpolate import interp2d
# Generate sample data
n = 10000
x = random.randn(n)
y = -x + random.randn(n)
# bin
nbins = 100
H, xedges, yedges = histogram2d(x, y, bins=nbins)
# Figure out centers of bins
def centers(edges):
return edges[:-1] + diff(edges[:2])/2
xcenters = centers(xedges)
ycenters = centers(yedges)
# Construct interpolator
pdf = interp2d(xcenters, ycenters, H)
# test
plt.pcolor(xedges, yedges, pdf(xedges, yedges))
Result:
Note that this will be linearly interpolated rather than step-wise. For a quicker version which assumes a regular grid, this will also work:
from numpy import meshgrid, vectorize
def position(edges, value):
return int((value - edges[0])/diff(edges[:2]))
#vectorize
def pdf2(x, y):
return H[position(yedges, y), position(xedges, x)]
# test - note we need the meshgrid here to get the right shapes
xx, yy = meshgrid(xcenters, ycenters)
plt.pcolor(xedges, yedges, pdf2(xx, yy))

Plancks Formula for Blackbody spectrum

I am trying to write a simple python code for a plot of intensity vs wavelength for a given temperature, T=200K.
So far I have this...
import scipy as sp
import math
import matplotlib.pyplot as plt
import numpy as np
pi = np.pi
h = 6.626e-34
c = 3.0e+8
k = 1.38e-23
def planck(wav, T):
a = 2.0*h*pi*c**2
b = h*c/(wav*k*T)
intensity = a/ ( (wav**5)*(math.e**b - 1.0) )
return intensity
I don't know how to define wavelength(wav) and thus produce the plot of Plancks Formula. Any help would be appreciated.
Here's a basic plot. To plot using plt.plot(x, y, fmt) you need two arrays x and y of the same size, where x is the x coordinate of each point to plot and y is the y coordinate, and fmt is a string describing how to plot the numbers.
So all you need to do is create an evenly spaced array of wavelengths (an np.array which I named wavelengths). This can be done with arange(start, end, spacing) which will create an array from start to end (not inclusive) spaced at spacing apart.
Then compute the intensity using your function at each of those points in the array (which will be stored in another np.array), and then call plt.plot to plot them. Note numpy let's you do mathematical operations on arrays quickly in a vectorized form which will be computationally efficient.
import matplotlib.pyplot as plt
import numpy as np
h = 6.626e-34
c = 3.0e+8
k = 1.38e-23
def planck(wav, T):
a = 2.0*h*c**2
b = h*c/(wav*k*T)
intensity = a/ ( (wav**5) * (np.exp(b) - 1.0) )
return intensity
# generate x-axis in increments from 1nm to 3 micrometer in 1 nm increments
# starting at 1 nm to avoid wav = 0, which would result in division by zero.
wavelengths = np.arange(1e-9, 3e-6, 1e-9)
# intensity at 4000K, 5000K, 6000K, 7000K
intensity4000 = planck(wavelengths, 4000.)
intensity5000 = planck(wavelengths, 5000.)
intensity6000 = planck(wavelengths, 6000.)
intensity7000 = planck(wavelengths, 7000.)
plt.plot(wavelengths*1e9, intensity4000, 'r-')
# plot intensity4000 versus wavelength in nm as a red line
plt.plot(wavelengths*1e9, intensity5000, 'g-') # 5000K green line
plt.plot(wavelengths*1e9, intensity6000, 'b-') # 6000K blue line
plt.plot(wavelengths*1e9, intensity7000, 'k-') # 7000K black line
# show the plot
plt.show()
And you see:
You probably will want to clean up the axes labels, add a legend, plot the intensity at multiple temperatures on the same plot, among other things. Consult the relevant matplotlib documentation.
You may also want to use the RADIS library, which allows you to plot the Planck function against wavelengths, or against frequency / wavenumber, if needed !
from radis import sPlanck
sPlanck(wavelength_min=135, wavelength_max=3000, T=4000).plot()
sPlanck(wavelength_min=135, wavelength_max=3000, T=5000).plot(nfig='same')
sPlanck(wavelength_min=135, wavelength_max=3000, T=6000).plot(nfig='same')
sPlanck(wavelength_min=135, wavelength_max=3000, T=7000).plot(nfig='same')
Just want to point out that there seems to be an equivalent of what OP wants to do in astropy:
https://docs.astropy.org/en/stable/api/astropy.modeling.physical_models.BlackBody.html
Unfortunately, it is not very clear to me yet how to get wavelength vs frequency based expression.

Categories