Surface plot in matplotlib - python

I am having trouble performing surface plot operation in Python, using the matplotlib library. Below is my code snippet
However, I get an error stating that 'Figure' object has no property 'projection'. Without using the projection property, I get an error that ax1 has no function called plot_surface
How can I resolve this error ?
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import pyautogui
from scipy import stats
x = pyautogui.size()
width = x.width
height = x.height
x = np.arange(0, 10, .1)
y = np.arange(0, 10, .1)
X, Y = np.meshgrid(x,y)
data = 2*(np.sin(X) + np.sin(3*Y))
fig, (ax, ax1) = plt.subplots(2, 1, projection='3d')
fig.set_figheight(height/100)
fig.set_figwidth(width/100)
fig.set_dpi(100)
im = ax.pcolormesh(X, Y, data, cmap='viridis')
cbar = plt.colorbar(im, ax=ax)
cbar.set_label('ColorbarLabel', size=15)
surf = ax1.plot_surface(X, Y, data, cmap='virdis')
cbar1 = plt.colorbar(surf, ax=ax1)
cbar1.set_label('Colorbar2', size=15)
ax.set_xlabel('x_label')
ax.set_ylabel('y_label')
ax.set_title('Title')

Seems like I can solve the problem by adding subplots seperately to the figure object. Is this the most efficient and correct way to achieve my goals ?
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import pyautogui
from scipy import stats
x = pyautogui.size()
width = x.width
height = x.height
x = np.arange(0, 10, .1)
y = np.arange(0, 10, .1)
X, Y = np.meshgrid(x,y)
data = 2*(np.sin(X) + np.sin(3*Y))
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
ax1 = fig.add_subplot(2, 1, 2, projection='3d')
fig.set_figheight(height/100)
fig.set_figwidth(width/100)
fig.set_dpi(100)
im = ax.pcolormesh(X, Y, data, cmap='viridis')
cbar = plt.colorbar(im, ax=ax)
cbar.set_ticks([0.2, 0.4, 0.6, 0.8])
cbar.set_ticklabels(["A", "B", "C", "D"])
cbar.set_label('ColorbarLabel', size=15)
surf = ax1.plot_surface(X, Y, data, cmap='jet')
cbar1 = plt.colorbar(surf, ax=ax1)
cbar.set_label('Colorbar2', size=15)
ax.set_xlabel('x_label')
ax.set_ylabel('y_label')
ax.set_title('Title')

Related

Python colorbar with errorbar

I am trying to plot x vs y data and trying to see the variation of x and y with respect to z using a colorbar.
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
ax.errorbar(x, y, x_err, y_err, fmt='*', elinewidth = 0.9, ecolor='black')
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
I need the errorbar to have the same color as that of the datapoint.
You could compute the ecolor from the same cmap. Not sure there aren't any solution to do that for you, but it doesn't cost much
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
# Rest of your code is yours. Only this line is added (and next line modified to use this "col" as ecolor
col=cm.viridis((np.array(z)-min(z))/(max(z)-min(z))) # RGBA colors from z
ax.errorbar(x, y, x_err, y_err, ecolor=col, fmt='*', elinewidth = 0.9)
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
plt.show()
Result

Plotting log function with two variables

I'm looking to plot some function but the logarithm function keeps giving me this error:
TypeError: only size-1 arrays can be converted to Python scalars
This is the code I'm using:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
%matplotlib notebook
def f10(x,y):
return x*math.log(y,2) + y*math.log(x,2)
x = np.linspace(-100, 100, 100)
y = np.linspace(-100, 100, 100)
#x = np.arange(-3.2, 3.2, 0.2)
#y = np.arange(-3.2, 3.2, 0.2)
X, Y = np.meshgrid(x, y)
Z = f10(X,Y)
fig = plt.figure(figsize = (10,10))
ax = plt.axes(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,cmap='jet', edgecolor = 'none')
ax.set_title("Surface", fontsize = 13)
ax.set_xlabel('x', fontsize = 11)
ax.set_ylabel('y', fontsize = 11)
ax.set_zlabel('Z', fontsize = 11)
plt.xlabel('x')
plt.ylabel('y')
func = np.vectorize(f10)
fig, ax = plt.subplots(1)
p=ax.contour(X, Y, func(X,Y))
fig.colorbar(surf)
plt.show()

Python - Plotting two 3D graphs with a contour map

I am trying to plot a figure in Python with two 3D graphs (same function, different angles) and a 2D contour map of the same function and I'm not sure why but the two first figures are okay and the contour map is weird, it appears at the bottom of the two first figures and the sizing is all weird (see the picture attached). Is there a way to place the map at the right of the 2 other figures and to resize it to make it more like a square?
Thank you for your help.
Here's my code :
import numpy as np
import matplotlib.pylab as plt
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(-5, 5, 0.01)
y = np.arange(-5, 5, 0.01)
X, Y = np.meshgrid(x, y)
Z = 5 + (10 * X**2 + 20 * Y**2) * np.exp((-X**2)-(Y**2)) + 3 *np.sin(X) - np.sin(Y)
fig = plt.figure(figsize=(15,5))
ax1 = plt.subplot(131, projection='3d')
surf1 = ax1.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax2 = plt.subplot(132, projection='3d')
surf2 = ax2.plot_surface(X, Y, Z, cmap=cm.coolwarm)
for angle in range(0,360):
ax2.view_init(20, angle)
plt.pause(.001)
ax3 = plt.subplot(133)
surf3 = ax3.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(surf3, fmt = '%.0f', inline=True, fontsize=8)
ax1.set_xlabel('X')
ax2.set_xlabel('X')
ax3.set_xlabel('X')
ax1.set_ylabel('Y')
ax2.set_ylabel('Y')
ax3.set_ylabel('Y')
ax1.set_zlabel('Z')
ax2.set_zlabel('Z')
plt.show()
Got it:
import numpy as np
import matplotlib.pylab as plt
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(-5, 5, 0.01)
y = np.arange(-5, 5, 0.01)
X, Y = np.meshgrid(x, y)
Z = 5 + (10 * X**2 + 20 * Y**2) * np.exp((-X**2)-(Y**2)) + 3 *np.sin(X) - np.sin(Y)
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(1, 3, 1, projection='3d')
surf1 = ax1.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax3 = fig.add_subplot(1, 3, 2)
surf3 = ax3.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(surf3, fmt = '%.0f', inline=True, fontsize=8)
ax2 = fig.add_subplot(1, 3, 3, projection='3d')
surf2 = ax2.plot_surface(X, Y, Z, cmap=cm.coolwarm)
for angle in range(0,360):
ax2.view_init(20, angle)
plt.pause(.001)
ax1.set_xlabel('X')
ax2.set_xlabel('X')
ax3.set_xlabel('X')
ax1.set_ylabel('Y')
ax2.set_ylabel('Y')
ax3.set_ylabel('Y')
ax1.set_zlabel('Z')
ax2.set_zlabel('Z')
plt.show()

python - how do I fix interpolate grid origin issues in matplotlib?

I have a data set with a small sample size of data. For example:
My code looks something like this:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import Rbf
df=pd.read_csv('test.csv')
df.head()
extent = x_extent = x_min, x_max, y_min, y_max = [df["X"].min()-1000, df["X"].max()+1000, df["Y"].min()-1000, df["Y"].min()+1000]
grid_x, grid_y = np.mgrid[x_min:x_max:100, y_min:y_max:100]
rbfi=Rbf(df["X"], df["Y"], df["Total"])
di=rbfi(grid_x, grid_y)
plt.scatter(grid_x, grid_y, s=10)
plt.figure(figsize=(15,15))
plt.imshow(di.T, origin="lower", extent=extent)
c2 = plt.scatter(df["X"], df["Y"], s=60, c=df["Total"], edgecolor='#ffffff66')
plt.colorbar(c2, shrink=0.6)
plt.show()
the result:
The result is a scatter plot of my points that appear to be in the correct place, but the interpolated grid is not covering the scatter points. So I think this has something to do with my origin not being correct, but I don't know how to fix this.
Two approaches here, one with a Delaunay triangulation, the other using the Radial Basis Function. Snippet and figure below.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.tri import Triangulation
from scipy.interpolate import Rbf
rng = np.random.default_rng()
X = rng.random(size=(15))
Y = rng.random(size=(15))
Total = rng.random(size=(15))
fig, (ax, bx) = plt.subplots(nrows=1, ncols=2, num=0, figsize=(16, 8))
tri = Triangulation(X, Y)
tctrf = ax.tricontourf(tri, Total)
gridY, gridX = np.mgrid[np.amin(Y):np.amax(Y):100 * 1j,
np.amin(X):np.amax(X):100 * 1j]
rbfi = Rbf(X, Y, Total, function='linear')
iTotal = rbfi(gridX, gridY)
bx.contourf(gridX, gridY, iTotal)
scat = ax.scatter(X, Y, s=60, c=Total, edgecolor='black')
fig.colorbar(scat, ax=ax)
scat = bx.scatter(X, Y, s=60, c=Total, edgecolor='black')
fig.colorbar(scat, ax=bx)
ax.set_aspect('equal')
bx.set_aspect('equal')
fig.tight_layout()
fig.savefig('so.png')
plt.show()

Python plt.axis('Equal') xlim

I have a simple 3D surface plot in which I want the axes to be equal in all directions.
I have the following piece of code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
X = np.array([-100, 0, 100])
Y = np.array([ 0, 10, 20])
X_grid, Y_grid = np.meshgrid(X,Y)
Z_grid = np.matrix('0 10 4;'
'1 11 3;'
'0 10 5')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X_grid, Y_grid, Z_grid, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=1, antialiased=True)
plt.axis('Equal')
which yields this plot:
I then have to manually zoom out to get proper axis limits.
I have tried plt.xlim(-100,100), but it doesn't seem to respond?
Also, the plt.axis('Equal') doesn't seem to apply to the z-axis?
The plot should look like this:
You can easily adapt the strategies from the link in the comment so the operations just affect the X-Y plane:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
X = np.array([-100, 0, 100])
Y = np.array([ 0, 10, 20])
X_grid, Y_grid = np.meshgrid(X,Y)
Z_grid = np.matrix('0 10 4;'
'1 11 3;'
'0 10 5')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X_grid, Y_grid, Z_grid, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=1, antialiased=True)
max_range = np.array([X_grid.max()-X_grid.min(), Y_grid.max()-Y_grid.min()]).max() / 2.0
mid_x = (X_grid.max()+X_grid.min()) * 0.5
mid_y = (Y_grid.max()+Y_grid.min()) * 0.5
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
plt.show()
Output:

Categories

Resources