How to convert scatter plot into a surface plot? - python

Beginner using python and I have a scatter plot (http://i.stack.imgur.com/sQNHM.png). What I want to do is produce a 3D plot that shows a spike in the Z direction at these points and 0 everywhere else.
This is the code I'm currently using:
plt.scatter(X, Y)
plt.show()
X, Y = np.meshgrid(X, Y)
Z = [1] * len(X)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.plot_surface(X, Y, Z)
plt.show()
This gives me a strange result (http://i.stack.imgur.com/7fLeT.png) that I'm not sure what to do to fix it.

You probably don't want to use the x and y values from your 2D plot as the input for meshgrid because you want this plot to be defined for all integer values of x and y in your range. The original x and y should define the location of the spikes if I understand your problem correctly. Here's a way to get a 3D plot with spikes of height 100 at defined locations:
from matplotlib import pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Create X, Y and Z arrays
x = range(0,250)
y = range(0,250)
X, Y = np.meshgrid(x, y)
Z = np.zeros((250,250))
# Locations of the spikes. These are some made up numbers.
dataX = np.array([25,80,90,145,180])
dataY = np.array([170,32,130,10,88])
# Set spikes to 100
Z[dataX,dataY] = 100
# Plot
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.plot_surface(X, Y, Z)
plt.show()

Related

Wireframing from an image using matplotlib

I'm trying to make a 3D representation of an image as a surface using wireframes with matplotlib.
ig= mpimg.imread('testIMG.png');
X = np.linspace(0,len(ig[0]),len(ig[0])); #List of discrete x values
Y = np.linspace(0,len(ig[1]),len(ig[1])); #List of discrete y values
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#Plot the wireframe
#I want to plot the image as f(x,y) and I can't understand why wireframe won't let me
ax.plot_wireframe(X, Y, ig[:,:,2], rstride=10, cstride=10)
plt.show()
The imread function gives me an MxNx3 array of M rows, N columns, and an RGB value for each point in the matrix. I don't understand how to use wireframe to plot that data properly. These z values aren't plotting what I expected (a checkerboard pattern), but instead a y=x line alternating between 0 and 1.
What do I need to do here? I want a series of cuboids in a 3D checkerboard pattern.
Image of what I have currently
You may use np.meshgrid(), so:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import mpl_toolkits.mplot3d
ig = mpimg.imread('testIMG.png')
x = np.linspace(0, ig.shape[1], ig.shape[1]) #List of discrete x values
y = np.linspace(0, ig.shape[0], ig.shape[0]) #List of discrete y values
X, Y = np.meshgrid(x, y)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#Plot the wireframe
#I want to plot the image as f(x,y) and I can't understand why wireframe won't let me
ax.plot_wireframe(X, Y, ig[:,:,2], rstride=10, cstride=10)
plt.show()

How to plot horizontal stack of heatmaps or a stack of grid?

I want to plot a stack of heatmaps, contour, or grid computed over time. The plot should like this,
I have tried this:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Z = np.meshgrid(x, x)
Y = np.sin(X)*np.sin(Z)
levels = np.linspace(-1, 1, 40)
ax.contourf(X, Y, Z, zdir='y')
ax.contourf(X, Y+3, Z, zdir='y')
ax.contourf(X, Y+7, Z, zdir='y')
ax.legend()
ax.view_init(15,155)
plt.show()
For one my plot looks ugly. It also does not look like what I want. I cannot make a grid there, and the 2d surfaces are tilted.
Any help is really appreciated! I am struggling with this.
Related stackoverflow:
[1] Python plot - stacked image slices
[2] Stack of 2D plot
How about making a series of 3d surface plots, with the data your wish to present in contour plotted as facecolor?
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Z = np.arange(-5, 5, 0.25)
X, Z = np.meshgrid(X, Z)
C = np.random.random(size=40*40*3).reshape((40, 40, 3))
ax.plot_surface(X, np.ones(shape=X.shape)-1, Z, facecolors=C, linewidth=0)
ax.plot_surface(X, np.ones(shape=X.shape), Z, facecolors=C, linewidth=0)
ax.plot_surface(X, np.ones(shape=X.shape)+1, Z, facecolors=C, linewidth=0)

Plotting a curve on the mesh surface along only a determined axis

I'm very new in Python and trying to plot a single curve on a surface.
Here is where I came so far and plotted a surface in s domain:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cmath
x = np.linspace(-400, 0, 100)
y = np.linspace(-100, 100, 100)
X, Y = np.meshgrid(x,y)
fc=50
wc=2*np.pi*fc
s = X + Y*1j
Z= abs(1/(1+s/wc))
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)
ax.plot(X, Y, Z)
plt.ylabel('Im')
plt.show()
I now need to plot the curve for X = 0 in different color which means the curve on the same surface along the imaginary axis. surf = ax.plot_surface(0, Y, Z) did not work. Does anybody have experience with such plot?
I'm assuming you meant you wanted to plot y=0 instead of x=0 (since x=0 would be pretty boring).
Since you want to plot a single slice of your data, you can't use the meshgrid format (or if you can, it would require some weird indexing that I don't want to figure out).
Here's how I would plot the y=0 slice:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cmath
x = np.linspace(-400, 0, 100)
y = np.linspace(-100, 100, 100)
X, Y = np.meshgrid(x,y)
fc=50
wc=2*np.pi*fc
s = X + Y*1j
Z= abs(1/(1+s/wc))
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)
# create data for y=0
z = abs(1/(1+x/wc))
ax.plot(x,np.zeros(np.shape(x)),z)
plt.ylabel('Im')
plt.show()

Python : Best way to draw 3d function with random x and y

I generated a 2d array, in each row, there is a random x, random y and f(x,y).
I chose random x and y because f(x, y) is very long to compute.
I used Axes3D from mpl_toolkits.mplot3d to draw the result :
ax.scatter(tableau[:,0], tableau[:,1], zs=tableau[:,2], c='r', marker='o')
The result is not useful. Impossible to understand the shape of f
Is there a better way to draw f(x,y)?
If your goal is to see the shape of your function better you can rotate the axes with matplotlib method view_init(elev=None, azim=None); it sets the elevation and azimuth of the axes angle . For example:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Test 3D function
X, Y, Z = axes3d.get_test_data(0.1)
ax.plot_wireframe(X, Y, Z, rstride=5, cstride=5)
ax.view_init(elev, azim)
plt.draw()
With elev=30 and azim=45:
With elev=30 and azim=90:
With elev=0 and azim=90:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
elev=70
azim=30
X, Y, Z = tableau[:,0], tableau[:,1], tableau[:,2]
ax.plot_wireframe(X, Y, Z, rstride=5, cstride=5)
ax.view_init(elev, azim)
plt.draw()

Applying colormaps to custom axis in Matplotlib 3D surface

I have timeseries data which I've segmented into hundreds of chunks. I solved the autocorrelation for each segment and plotted them:
# plot superimposed
fig = plt.figure()
color = iter(plt.cm.Set2(np.linspace(0,1,num_segs)))
seg_iterator = df.iterrows()
for index, seg in seg_iterator: # iterate over dataframe
c=next(color)
sns.plt.plot(seg, color=c)
Next, I plotted them as a 3D surface:
# plot as a surface
surfacefig = plt.figure()
surfaceax = surfacefig.gca(projection='3d')
X = np.arange(LAGS+1)
Y = np.arange(num_segs)
X, Y = np.meshgrid(X, Y)
surfaceax.plot_surface(X, Y, df, cmap=plt.cm.Set2)
plt.show()
How can I map colors to row index (rather than z-values)? I'd like to preserve the colors of the lines.
Update with result:
# updated lines. Make sure XX and YY are floats
surf = surfaceax.plot_surface(XX, YY, df, shade=False,
facecolors=plt.cm.Set2((YY-YY.min()) / (YY.max()-YY.min())),
cstride=1, rstride=5, alpha=0.7)
plt.draw() # you need this to get the edge color
line = np.array(surf.get_edgecolor())
surf.set_edgecolor(line*np.array([0,0,0,0])+1)
You can try this:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X = np.linspace(-np.pi, np.pi, 200, endpoint=True)
Y = np.linspace(-np.pi, np.pi, 200, endpoint=True)
XX, YY = np.meshgrid(X,Y)
Z = np.cos(XX)*np.cos(YY)
fig = plt.figure()
ax1 = plt.subplot2grid((1,2), (0,0), projection='3d')
ax2 = plt.subplot2grid((1,2), (0,1), projection='3d')
surf = ax1.plot_surface(XX, YY, Z,
cmap=plt.cm.Set2)
surf2 = ax2.plot_surface(XX, YY, Z, shade=False,
facecolors=plt.cm.Set2((XX-XX.min())/(XX.max()-XX.min()))
)
Where on the second plot, you set the facecolors as being function of XX, instead of Z by default. You need to rescale your XX values between 0 and 1 or the colormap will be saturated outside 0 and 1. You also need to remove the shade which is removed when yous use cmap (in the first plot).
However, for some unknown reasons, the lines disappear.
You can add them back with:
plt.draw() # you need this to get the edge color
lines = np.array(surf2.get_edgecolor())
surf2.set_edgecolor(lines*np.array([0,0,0,0])+1) # make lines white, and keep alpha==1. It's an array of colors like this: [r,g,b,alpha]
It gives:
HTH

Categories

Resources