fill the common area under both curve - python

How I can fill the common area under both the curve?
import matplotlib.pyplot as plt
import numpy as np
import scipy.special as sp
x = np.linspace(-4, 4, num=1000)
r = abs(x)
zeta = 1.0
psi_STO = (zeta**3 / np.pi)**(0.5) * np.exp(-zeta * r)
plt.figure(figsize=(4, 3))
plt.plot(x, psi_STO, color="C0")
plt.plot(x + 3, psi_STO, color="C0")
plt.show()
If I use:
plt.fill_betweenx(psi_STO, -1, 4, color="C1")
I am getting a plot as:

You can use fill_between. As your Xs are not aligned, you need to make a bit of calculations first to find the common range. This will depend on the number of points in the linspace. Here, I computed it manually: as the shift is of 3, there are 375 points difference (250 per unit).
import matplotlib.pyplot as plt
import numpy as np
import scipy.special as sp
x = np.linspace(-4, 4, num=1000)
r = abs(x)
zeta = 1.0
psi_STO = (zeta**3 / np.pi)**(0.5) * np.exp(-zeta * r)
plt.figure(figsize=(4, 3))
plt.plot(x, psi_STO, color="C0")
plt.plot(x + 3, psi_STO, color="C0")
x_common = (x+3)[:-375]
min_common = np.min([psi_STO[:-375], psi_STO[375:]], axis=0)
plt.plot(x_common, min_common, color='r')
plt.fill_between(x_common,min_common, color="#FFB0B0")
plt.show()
output:

This?
dx = 3 # x shift
di = int(dx/(x[1]-x[0])) # index shift
plt.fill_between(x[di:], np.minimum(psi_STO[:-di], psi_STO[di:]))

Related

Fixing K nearest neighbor algorithm function in Python

I modified a function based on a nearest neighbor algorithm that takes the parameters x and y from a list of randomly generated values to plot points on a graph based, but the edges are being plotted out wrong and I can't figure out why.
Here is the original algorithm I based my code on
import matplotlib.pyplot as plt
import numpy as np
xy = np.random.rand(40, 2)
plt.figure(figsize=(8,8))
dist_sq = np.sum((xy[:,np.newaxis,:] - xy[np.newaxis,:,:]) ** 2, axis=-1)
#nearest = np.argsort(dist_sq, axis=1)
K = 1
nearest_partition = np.argpartition(dist_sq, K+1, axis=1)
plt.figure(figsize=(8,8))
#plt.scatter(xy[:,0], xy[:,1], s=40)
for i in range(xy.shape[0]):
for j in nearest_partition[i, :K+1]:
plt.plot(*zip(xy[j], xy[i]), color='black')
and here is my function
import matplotlib.pyplot as plt
import numpy as np
def nearest_neighbor_graph(x, y, k, pcolor='blue', psize=20, ecolor='black', figsize=(6,6)):
plt.figure(figsize=(6, 6))
plt.scatter(x, y, psize, color = pcolor)
dist_sq = np.sum((xy[:,np.newaxis,:] - xy[np.newaxis,:,:]) ** 2, axis=-1)
nearest = np.argsort(dist_sq, axis=1)
#nearest_partition = np.argpartition(dist_sq, k + 1, axis=1)
for i in range(xy.shape[0]):
for j in nearest[i, :k + 1]:
plt.plot(*zip(xy[i], xy[j]), color= ecolor)
np.random.seed(10)
xy = np.random.rand(2, 40)
nearest_neighbor_graph(xy[0], xy[1], 1, ecolor='red', psize=50)
nearest_neighbor_graph(xy[0], xy[1], 2, pcolor='green', psize=100, ecolor='black')
In my function, when I get to the nearest_partition line I get an error so I use nearest instead in its place in the bottom loop
for i in range(xy.shape[0]):
for j in nearest[i, :k + 1]:
plt.plot(*zip(xy[i], xy[j]), color= ecolor)
Any help would be greatly appreciated, thanks
You were really close. The error message was the clue:
ValueError: kth(=2) out of bounds (2)
checked the array size with np.shape() and it was 40x40, so then checked the syntax which was incorrect. You can see the corrected line.
so this works:
import matplotlib.pyplot as plt
import numpy as np
def nearest_neighbor_graph(x, y, k, pcolor='blue', psize=20, ecolor='black', figsize=(6,6)):
plt.figure(figsize=(6, 6))
plt.scatter(x, y, psize, color = pcolor)
dist_sq = np.sum((xy[:,np.newaxis,:] - xy[np.newaxis,:,:]) ** 2, axis=-1)
# nearest = np.argsort(dist_sq, axis=1)
nearest_partition = np.argpartition(dist_sq, kth= 1, axis=1)
for i in range(xy.shape[0]):
for j in nearest_partition[i, :k + 1]:
plt.plot(*zip(xy[i], xy[j]), color= ecolor)
np.random.seed(10)
xy = np.random.rand(2, 40)
nearest_neighbor_graph(xy[0], xy[1], 1, ecolor='red', psize=50)
nearest_neighbor_graph(xy[0], xy[1], 2, pcolor='green', psize=100, ecolor='black')
Here are the resulting graphs:

Plot surface where Z depends on a vector of X and Y

I'm currently working on a small python script which can be used to interpolate points with a radial basis function approach. Therefore I would like to plot a surface where the Z value is calculated by a vector which depends on X and Y.
The formula I need to implement looks like this:
My current approach is the following:
import numpy as np
import matplotlib.pyplot as plt
def phi(x):
return np.exp(- np.power(x, 2))
fig = plt.figure(figsize=(8,7))
ax = fig.add_subplot(projection='3d')
x = np.arange(0, 6, 0.25)
y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(x, y)
Z = 0.49 * phi(np.linalg.norm(np.array([[1,1], [X,Y]]))) + \
0.79 * phi(np.linalg.norm(np.array([[2,3], [X,Y]]))) + \
0.39 * phi(np.linalg.norm(np.array([[4,2], [X,Y]])))
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
plt.xlim(0, 6)
plt.ylim(0, 6)
plt.show()
Something seems to be wrong with the parameter that I pass to the phi()-function but I'm not sure what it is.
So how can I calculate the Z value correctly?
Note: I found a similar question, but the answer did not help me in my case.
As #Mateo Vial mentioned in the comments, the simplest approach is to calculate the norm with the pythagorean formula. The working code looks like this:
import numpy as np
import matplotlib.pyplot as plt
def phi(x):
return np.exp(- np.power(x, 2))
fig = plt.figure(figsize=(8,7))
ax = fig.add_subplot(projection='3d')
x = np.arange(0, 6, 0.25)
y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(x, y)
Z = 0.49 * phi(np.sqrt((1-X)**2+(1-Y)**2)) + \
0.79 * phi(np.sqrt((2-X)**2+(3-Y)**2)) + \
0.39 * phi(np.sqrt((4-X)**2+(2-Y)**2))
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
plt.xlim(0, 6)
plt.ylim(0, 6)
plt.show()
And now the result is a good interpolation with a radial basis function.
Here's one way to refactor what you have:
import numpy as np
import numpy.linalg as la
import matplotlib.pyplot as plt
def phi(x):
return np.exp(-np.power(x, 2))
fig, ax = plt.subplots(figsize=(8, 7))
x = y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(x, y)
xy = np.stack([X.flat, Y.flat]).T
Z = (0.49 * phi(la.norm(np.array([[1, 1]]) - xy, axis=1)) +
0.79 * phi(la.norm(np.array([[2, 3]]) - xy, axis=1)) +
0.39 * phi(la.norm(np.array([[4, 2]]) - xy, axis=1))
)
surf = ax.imshow(Z.reshape(X.shape))
plt.show()
This produces:

How to plot normal vectors in each point of the curve with a given length?

How to plot normal vectors in each point of the curve with a given length?
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
x = np.linspace(-1, 1, 100)
y = x**2
ax.set_ylim(-0.3, 1.06)
ax.plot(x, y)
plt.show()
To plot the normals, you need to calculate the slope at each point; from there, you get the tangent vector that you can rotate by pi/2.
here is one approach using python i/o np, which makes it probably easier to understand at first.
Changing the length will adjust the size of the normals to properly scale with your plot.
import matplotlib.pyplot as plt
import numpy as np
import math
def get_normals(length=.1):
for idx in range(len(x)-1):
x0, y0, xa, ya = x[idx], y[idx], x[idx+1], y[idx+1]
dx, dy = xa-x0, ya-y0
norm = math.hypot(dx, dy) * 1/length
dx /= norm
dy /= norm
ax.plot((x0, x0-dy), (y0, y0+dx)) # plot the normals
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
x = np.linspace(-1, 1, 100)
y = x**2
ax.set_ylim(-0.3, 1.06)
ax.plot(x, y)
get_normals()
plt.show()
or longer normals, directed downwards: get_normals(length=-.3)
(use ax.set_aspect('equal') to maintain angles)
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
x = np.linspace(-1, 1, 100)
y = x**2
# Calculating the gradient
L=.1 # gradient length
grad = np.ones(shape = (2, x.shape[0]))
grad[0, :] = -2*x
grad /= np.linalg.norm(grad, axis=0) # normalizing to unit vector
nx = np.vstack((x - L/2 * grad[0], x + L/2 * grad[0]))
ny = np.vstack((y - L/2 * grad[1], y + L/2 * grad[1]))
# ax.set_ylim(-0.3, 1.06)
ax.plot(x, y)
ax.plot(nx, ny, 'r')
ax.axis('equal')
plt.show()

Create the equivalent of np.meshgrid using for loops

This code outputs a plot of e^(-r^2) on a 2-D x,y grid :
import numpy as np
import matplotlib.pyplot as plt
x1d = np.arange(-3, 3, 0.006)
y1d = np.arange(-3, 3, 0.006)
x2d, y2d = np.meshgrid(x1d, y1d)
r2d = x2d**2 + y2d**2
z = np.exp(-r2d)
plt.imshow(z, extent = (3, -3 , 3 , -3))
plt.title("A 2-D Image plot")
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.savefig('2dexp_array.pdf', format ='pdf')
plt.show(block = False)
I want to change the code so that instead of using np.meshgrid , it uses for loops to generate the 2d grid space.
Something like :
import numpy as np
import matplotlib.pyplot as plt
x1d = np.arange(-3, 3, 0.006)
y1d = np.arange(-3, 3, 0.006)
z = np.zeros([2000, 2000])
and then using for loops to replace the zeros in z with the correct values according to x1d , y1d.
But I'm not sure how to use a for loop to mirror the function of meshgrid.
If someone could point me in the right direction I would appreciate it
Thanks
This should do:
for i,x in enumerate(x1d):
for j,y in enumerate(y1d):
z[i,j] = np.exp(-(x**2 + y**2))

How can I fix polar RGB imshow's xticks?

This code:
def complex_to_rgb(complex_data, invert=False):
from numpy import angle, max, pi, sin, zeros
phase = angle(complex_data)
amplitude = abs(complex_data)
amplitude = amplitude/max(max(amplitude))
A = zeros((complex_data.shape[0], complex_data.shape[1], 3))
A[:,:,0] = .5*(sin(phase)+1)*amplitude
A[:,:,1] = .5*(sin(phase+pi/2)+1)*amplitude
A[:,:,2] = .5*(-sin(phase)+1)*amplitude
if(invert):
return 1-A
else:
return A
import numpy as np
from matplotlib.pyplot import figure
N = 1024
x = np.linspace(-1, 1, N)
y = np.linspace(-1, 1, N)
X,Y = np.meshgrid(x,y)
R = np.sqrt(X*X + Y*Y)
PHI = np.arctan2(Y, X)
fig = figure()
ax = fig.add_subplot(212, polar=True)
ax.imshow(complex_to_rgb(R*np.exp(1j*PHI) * (R<1), invert=True))
ax.set_xticks([-.5, 0, np.pi/2, np.pi, 3*np.pi/2])
ax.set_yticks([0, N/3, 2*N/3, N])
ax.set_xticklabels(['', '$0$', r'$\pi/2$', r'$\pi$', r'$3\pi/2$'])
ax.set_yticklabels([])
fig.show()
Generates a nice HSV legend plot. Now I'd like to remove the -.5 xtick, but that seems to mess everything up. Anyone know how to fix this? I already reported it as a bug
As described in the bug report, I can place the radial axis anywhere I want by specifying an explicit extent to imshow. Additionally, rgrids can be used to fix the angle of the tick labels.
def complex_to_rgb(complex_data, invert=False):
from numpy import angle, max, pi, sin, zeros
phase = angle(complex_data)
amplitude = abs(complex_data)
amplitude = amplitude/max(max(amplitude))
A = zeros((complex_data.shape[0], complex_data.shape[1], 3))
A[:,:,0] = .5*(sin(phase)+1)*amplitude
A[:,:,1] = .5*(sin(phase+pi/2)+1)*amplitude
A[:,:,2] = .5*(-sin(phase)+1)*amplitude
if(invert):
return 1-A
else:
return A
import numpy as np
from matplotlib.pyplot import figure
N = 1024
x = np.linspace(-1, 1, N)
y = np.linspace(-1, 1, N)
X,Y = np.meshgrid(x,y)
R = np.sqrt(X*X + Y*Y)
PHI = np.arctan2(Y, X)
fig = figure()
ax = fig.add_subplot(111, polar=True)
ax.imshow(complex_to_rgb(R*np.exp(1j*PHI) * (R<1), invert=True), extent=[0,2*np.pi, 0,1024])
ax.set_rgrids([1,N/3,2*N/3], angle=45)
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2])
ax.set_yticks([0, N/3, 2*N/3, N])
ax.set_xticklabels([r'$0$', r'$\pi/2$', r'$\pi$', r'$3\pi/2$'])
ax.set_yticklabels([r'0', r'$1/3$', r'$2/3$', '1'])
fig.show()
Which results in:

Categories