Contour plot of a multivariate function - python

I have a multivariate function
X is (2, 1), A(100, 2), and b is (100, 1).
How can I plot the contour plot of it in python? for a simple case like Z = X^2 + Y^2 I have this code, but I don't think it can work for my problem.
x, y = np.linspace(-3, 3, 400), np.linspace(-3, 3, 400)
XX, YY = np.meshgrid(x, y)
Z = (XX ** 2 + YY ** 2)
fig, ax = plt.subplots()
ax.contour(XX, YY, Z)
How can I plot contour of my function?

I assumed that in the pictured formula x is the same as X, which represents the coordinates of a point in a 2D plane.
Then, with np.meshgrid you create the usual grid of coordinates over which evaluating the function, xx and yy. At this points, you need to combine them into a matrix X of 2 rows (representing x and y coordinates) and as many columns as necessary.
Finally, you evaluate the function over each column of X.
import numpy as np
import matplotlib.pyplot as plt
# create example data
x = y = np.linspace(0, 2 * np.pi, 100)
A = np.stack([np.cos(x), np.sin(x * y)]).T
b = np.cbrt(x * y)
print("A.shape = ", A.shape)
print("b.shape = ", b.shape)
# define the function
f = lambda X: np.linalg.norm(b - A # X, 2)**2
# creates the coordinates over which the function
# will be evaluated
x = y = np.linspace(-np.pi, np.pi, 200)
xx, yy = np.meshgrid(x, y)
# assemble the coordinates into a "vector of coordinates"
X = np.stack([xx, yy]).reshape(2, -1)
print("X.shape = ", X.shape)
# apply the function f on each pair of coordinates
Z = np.apply_along_axis(f, 0, X).reshape(xx.shape)
print("Z.shape = ", Z.shape)
fig, ax = plt.subplots()
c = ax.contourf(xx, yy, Z)
fig.colorbar(c)
plt.show()

Related

Scipy RegularGridInterpolator turns interpolated vector field

The task:
I am trying to interpolate a vector field on a regular grid, i.e.:
The issue:
I am using the RegularGridInterpolator from scipy to do this. However, it seems that the resulting vector field is turned with respect to the original:
Anyone knows why?
Python code to reproduce example:
from scipy.interpolate import RegularGridInterpolator
import matplotlib.pyplot as plt
import numpy as np
# ORIGINAL
# Number of points (NxN)
N = 50
# Boundaries
ymin = -2.; ymax = 2.
xmin = -2.; xmax = 2.
# Create Meshgrid
x = np.linspace(xmin,xmax, N)
y = np.linspace(ymin,ymax, N)
xx, yy = np.meshgrid(x, y)
# Vector Field
Fx = np.cos(xx + 2*yy)
Fy = np.sin(xx - 2*yy)
# Plot vector field
fig, ax = plt.subplots()
ax.quiver(x, y, Fx, Fy)
plt.title("Original")
plt.show()
# REDUCED
# Number of points (NxN)
N = 10
# Boundaries
ymin = -2.; ymax = 2.
xmin = -2.; xmax = 2.
# Create Meshgrid
x = np.linspace(xmin,xmax, N)
y = np.linspace(ymin,ymax, N)
xx, yy = np.meshgrid(x, y)
# Vector Field
Fx = np.cos(xx + 2*yy)
Fy = np.sin(xx - 2*yy)
# Plot vector field
fig, ax = plt.subplots()
ax.quiver(x, y, Fx, Fy)
plt.title("Reduced")
plt.show()
# INTERPOLATED VERSION BASED ON REDUCED
# Iterpolate
my_interpolating_function_x = RegularGridInterpolator((x, y), Fx)
my_interpolating_function_y = RegularGridInterpolator((x, y), Fy)
# Create Meshgrid
N = 50
x = np.linspace(xmin,xmax, N)
y = np.linspace(ymin,ymax, N)
grid = np.meshgrid(x, y)
new_points = np.vstack(list(map(np.ravel, grid))).T
# Interpolate
F_x_inter = my_interpolating_function_x(new_points)
F_y_inter = my_interpolating_function_y(new_points)
# reshape
F_x_inter = np.reshape(F_x_inter,(50,50))
F_y_inter = np.reshape(F_y_inter,(50,50))
#plot
fig, ax = plt.subplots()
ax.quiver(x, y, F_x_inter, F_y_inter)
plt.title("Interpolated")
plt.show()

How to create a numpy array filled with average value of a vector

I am not sure how to phrase my question in any way better. Basically, I have three lists of the same length x, y and z and I want to fill a 2D numpy array in the z/y plane with the average of the associated z values.
Here is how I can achieve what I wan to do:
import numpy as np
import matplotlib.pyplot as plt
x = [37.59390426045407, 38.00530354847739, 38.28412244348653, 38.74871247986305, 38.73175910429809, 38.869008864244016, 39.188234404976555, 39.92835838352555, 40.881394113153334, 41.686136269465884]
y = [0.1305391767832006, 0.13764519613447768, 0.14573326951792354, 0.15090729309032114, 0.16355823707239897, 0.17327106424274763, 0.17749746339532224, 0.17310384614773594, 0.16545780437882962, 0.1604752704890856]
z = [0.05738534353865021, 0.012572155256903583, -0.021709582561809437, -0.11191337750722108, -0.07931921785775153, -0.06241610118871843, 0.014216349927058225, 0.042002641153291886, -0.029354425271534645, 0.061894011359833856]
n = 5
image = np.zeros(shape=(n,n))
# Fill the 2D array
x0 = min(x)
y0 = min(y)
dx = (max(x) - min(x))/n
dy = (max(y) - min(y))/n
# Loop over each 2D cell
for index_x in range(n):
for index_y in range(n):
# find the limits of the cell
x1 = x0 + index_x * dx
x2 = x0 + (index_x+1) * dx
y1 = y0 + index_y * dy
y2 = y0 + (index_y+1) * dy
# find the points of z that lie within the range of the cell
vec_z = [z[idx] for idx in range(len(z)) if x[idx]>=x1 and x[idx]<x2 and y[idx]>=y1 and y[idx]<y2]
if vec_z:
image[index_x, index_y] = np.mean(vec_z)
# In the end, used to create a surface plot
fig, ax = plt.subplots()
ax.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
plt.show()
Is there a more easy way to achieve this? I can imagine there is a numpy method for that.
If I understand correctly what you want to do, maybe a 2D interpolation from scipy.interpolate.interp2d is what you are looking for.
You define the interpolation function of your points:
f = interp2d(x = x, y = y, z = z)
Then you define the X and Y meshgrid:
N = 50
x_axis = np.linspace(np.min(x), np.max(x), N)
y_axis = np.linspace(np.min(y), np.max(y), N)
X, Y = np.meshgrid(x_axis, y_axis)
Finally you can compute Z interpolated values on the meshgrid:
Z = np.zeros((N, N))
for i in range(N):
for j in range(N):
Z[i, j] = f(X[i, j], Y[i, j])
If you plot in 3D the interpolated surface, you get:
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
ax.plot_surface(X, Y, Z, cmap = 'jet', shade = False)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
Interpolated surface compared to interpolation data points:
ax.scatter(x, y, z, color = 'black', s = 100, alpha = 1)

Finding intersection co-ordinates of 2 contours

Using "Finding intersection of two contour plots in Python"
as a guide I get the following error message (code follows):
<ipython-input-98-993ccd512742> in <module>
9
10
---> 11 intersection_example = findIntersection(c1,c2)
12
<ipython-input-97-995cbb9fd0d0> in findIntersection(contour1, contour2)
2
3 def findIntersection(contour1,contour2):
----> 4 p1 = contour1.collections[0].get_paths()[0]
5 v1 = p1.vertices
6
IndexError: list index out of range
The first code sample below gives me a 3D contour plot without error:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
fig.set_size_inches(18.5, 10.5) #, forward=True)
ax = plt.axes(projection='3d')
x = np.linspace(0, 21, 20)
y = np.linspace(0, 21, 20)
X, Y = np.meshgrid(x, y)
ax.contour3D(X, Y, ((X - 5) * (Y - 5) - 25), 29, cmap='winter')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z');
#fig.add_subplot(ax.contour3D(X, Y, Z2, 70, cmap='winter')) #binary'))
ax.contour3D(X, Y, (X**2 + Y**2 - 400), 29, cmap='autumn')
ax.set_title('Contour3D: Using meshgrid X Y ')
The above produces:
This next sample is the problem piece of code that uses contour (rather than contour3D) and results in the error:
IndexError: list index out of range
This is also the error generated when findIntersection is called with undefined parameters.
from shapely import geometry
def findIntersection(contour1,contour2):
p1 = contour1.collections[0].get_paths()[0]
v1 = p1.vertices
p2 = contour2.collections[0].get_paths()[0]
v2 = p2.vertices
poly1 = geometry.LineString(v1)
poly2 = geometry.LineString(v2)
intersection = poly1.intersection(poly2)
return intersection
figtst2 = plt.figure()
figtst2.set_size_inches(18.5, 10.5) #, forward=True)
ax2 = plt.axes(projection='3d')
c1 = ax2.contour(X,Y,((X - 5) * (Y - 5) - 25),1,colors='green', linewidths=3)
c2 = ax2.contour(X,Y,(X**2 + Y**2 - 400),1,colors='orange', linewidths=3)
ax2.set_title('Contour Using meshgrid X Y & looking for intersections')
# Error is generated on the next line
intersection_example = findIntersection(c1,c2)
# where coordinates can be accessed by
intersection_example.x ##get x points
intersection_example.y ##get y points
list(intersection_example.coords) ## get in [x,y] formatting
Plotting ax2 produces:
Note: If I use the linear space x and y rather than the mesh grid X and Y I get:
TypeError: Input z must be a 2D array.
I developed an answer that is a bit of a fudge , so please let me know if there is a way of doing it all in 3D.
The fudge is to do a 2D plot to get my intersection coordinates, then I do a 3D plot and use what I found in the 2D plot (see Jupyter notebook code )
from shapely import geometry
fig2 = plt.figure()
fig2.set_size_inches(18.5, 10.5) #, forward=True)
#plt.axes(projection='3d') # 3D gives no vertices "list index out of range"
tau = np.arange(0,23,1)
x,y= np.meshgrid(tau,tau)
cs = plt.contour(x, y, np.array((x - 5) * (y - 5) - 25), [1],colors='k')
cs2 = plt.contour(x, y, np.array((x**2 + y**2 - 400)), [1],colors='k') #x**2 + y**2 - 400
from shapely.geometry import LineString
v1 = cs.collections[0].get_paths()[0].vertices
v2 = cs2.collections[0].get_paths()[0].vertices
ls1 = LineString(v1)
ls2 = LineString(v2)
points = ls1.intersection(ls2)
print('points', np.array(points))
This gives following image
The 3D code is;
def fhyp(x, y):
return ((x - 5) * (y - 5) - 25)
x = np.linspace(0, 21, 20)
y = np.linspace(0, 21, 20)
X, Y = np.meshgrid(x, y)
Z = fhyp(X, Y)
def fcirc(x, y):
return (x**2 + y**2 - 400)
x = np.linspace(0, 21, 20)
y = np.linspace(0, 21, 20)
X, Y = np.meshgrid(x, y)
Z2 = fcirc(X, Y)
fig = plt.figure()
fig.set_size_inches(18.5, 10.5) #, forward=True)
ax = plt.axes(projection='3d')
x = np.linspace(0, 21, 20)
y = np.linspace(0, 21, 20)
X, Y = np.meshgrid(x, y)
ax.contour3D(X, Y, Z, 1, cmap='winter') #4th parm was 29 to give 29 contour lines
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z');
#
ax.contour3D(X, Y, Z2, 1, cmap='autumn')
ax.set_title('Contour3D: Using meshgrid X Y ')
from scipy import optimize
def f(p):
x, y = p
e1 = ((x - 5) * (y - 5) - 25)
e2 = (x**2 + y**2 - 400)
return e1, e2
x2, y2 = optimize.fsolve(f, (5, 5))
zval = ((x2 - 5) * (y2 - 5) - 25)
print(x2,y2, zval)
vals = [x2,y2,zval]
result = np.array(vals)
print(result)
plt.plot([result[0]],[result[1]],[result[2]], "rx")
for i in range(5):
x = [18.80452816482531,18.80452816482531]
y = [6.810999963323182, 6.810999963323182]
z = [-400,400]
plt.plot(x,y,z,'k--',alpha=0.8, linewidth=0.5)

How to plot a curve for a function in a 3D graphic - Python

I have this function:
z = 0.000855995633558468*x**2 + 0.0102702516120239*x + 0.00451027901725375*y**2 - 2.23785431578513*y + 251.029058292935
I also have lists (X, Y, Z) of the coordinates of the points from this function. Then I made this code to do a plot, of that coordinates:
fig = plt.figure()
ax = fig.gca(projection='3d')
plt.plot(X, Y, Z)
plt.show()
As you can see, with this code, I join the points by segments. How can I plot the curve that passes through those points?
In short, Python does not know how all xyz points need to be connected to each other to create a surface, so it just plots lines between them.
If you want to plot a surface whose z-coordinates are a function of its x and y coordinates you need to create a grid of all the possible combinations of xy coordinates and get the resulting z-grid. Then you can plot the grids.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
def z_func(x, y):
z = 0.000855995633558468 * x ** 2 + 0.0102702516120239 * x + \
0.00451027901725375 * y ** 2 - 2.23785431578513 * y + \
251.029058292935
return z
# Creates a 1D array of all possible x and y coordinates
x_coords = np.linspace(-30, 30, 100)
y_coords = np.linspace(180, 220, 100)
# Creates 2D array with all possible combinations of x and y coordinates,
# so x_grid.shape = (100, 100) and y_grid.shape = (100, 100)
[x_grid, y_grid] = np.meshgrid(x_coords, y_coords)
# Evaluates z at all grid points
z_grid = z_func(x_grid, y_grid)
# Plotting
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x_grid,y_grid,z_grid)
plt.show()

Contour plot in python [duplicate]

This question already has answers here:
Make contour of scatter
(3 answers)
Closed 5 years ago.
I have 3 lots of data. These are x and y values as well as a temperature value for each xy point. I would like to plot each point and interpolate the area between points to get a continuous surface. The issue I have is specifying the temperature values. I can't get it to work with an equal number of x,y and z (temperature) values and all the examples I can find online use a function of x and y to create z or have z values for every point on an xy grid.
Is there a simple way to do this?
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots()
x = np.linspace(0, 1, 100)
y = np.linspace(0,1,100)
X, Y = np.meshgrid(x, y)
#Z = np.sin(X)*np.sin(Y) # want to specify not an equation
Z = np.linspace(1,2,100)
levels = np.linspace(-1, 1, 40)
cs = axs.contourf(X, Y, Z, levels=levels)
fig.colorbar(cs, ax=axs, format="%.2f")
plt.show()
Update:
Here is what I have so far. I still need to work out a good method to fill in the area between points. Does anyone have any ideas?
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots()
# create a grid in the correct shape / size
x = np.linspace(0, 1, 3)
y = np.linspace(0,1,3)
X, Y = np.meshgrid(x, y)
# specify and change the relevent areas
y = [1,2,0] # location of point in x direction
x =[2,1,1] #location of point in y direction
z = [40,30,20] #temperature
Z = np.arange(1,10).reshape((3,3))
Z[y,x] = z
levels = np.linspace(0, 40, 40)
cs = axs.contourf(X, Y, Z, levels=levels)
fig.colorbar(cs, ax=axs, format="%.2f")
plt.show()
The reason people use a function of x and y is because your Z value has to be a function of x and y. In your test code Z is 1D but it needs to be 2D to plot the contours.
If you have Z (temperature) values that have the same shape as your x and y coordinates then it should work.
x = np.linspace(0, 1, 100)
y = np.linspace(0,1,100)
X, Y = np.meshgrid(x, y)
#Z = np.sin(X)*np.sin(Y) # want to specify not an equation
Z = np.linspace(1,2,100)
print X.shape
print Z.shape
(100L,100L)
(100L)

Categories