So I have an array of values that I am trying to plot using the plot_surface command. Specifically I have a 30x30 array with one in the middle and zeros elsewhere. When I plot it this is what I obtain:
I would like however for the value to be represented as a cuboid. Is that possible?
Thank you
edit: Code that shows the figure
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
N=30
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(0, N)
z = np.zeros((N,N))
z[15,15] = 1
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, z, cmap='YlOrBr')
plt.show(block=False)
I think a 3D bar plot will give what you're looking for.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
N=30
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(0, N)
z_bottom = np.zeros((N,N))
z_top = z_bottom.copy()
z_top[15,15] = 1
X, Y = np.meshgrid(x, y)
ax.bar3d(X.ravel(), Y.ravel(), z_bottom.ravel(), 1, 1, z_top.ravel())
plt.show(block=False)
The full documentation is here if you want to play with the colors and so forth.
Related
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()
I am trying to make a 3d surface plot of experimental data using matplotlib. I would like to plot different Z values against the same X and Y axes. When I try the simple code below, I get the error
"plot_surface() missing 1 required positional argument: 'Z' ".
It seems that the Axes3D package only work if Z is given as a function of X and Y, rather than an actual data matrix. Does anybody know a way around this?
Please note that the Zmatrix that I need is actual data, but I just used a random matrix for illustration here.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
X=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
Y= [0,2500,5000,7500,10000,15000,20000,25000,30000,35000,40000,45000,50000,55000,60000,65000,70000]
Zmatrix=np.random.rand(len(X),len(Y))
Axes3D.plot_surface(X,Y,Zmatrix)
There were sone issues with your code:
First you have to get a meshgrid of X and Y (all combinations as matrices). Next swap len(X) and len(Y) inside the Zmatrix. And first define ax = Axes3D(plt.gcf()) and plot_surface afterwards on ax.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
X=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
Y= [0,2500,5000,7500,10000,15000,20000,25000,30000,35000,40000,45000,50000,55000,60000,65000,70000]
Xm, Ym = np.meshgrid(X, Y)
Zmatrix=np.random.rand(len(Y),len(X))
ax = Axes3D(plt.gcf())
ax.plot_surface(Xm, Ym, Zmatrix)
Here is an example of surface plot.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import random
def fun(x, y):
return x**2 + y
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-3.0, 3.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array([fun(x,y) for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)
ax.plot_surface(X, Y, Z)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
I have searched for this in google, but found solutions for 2d points in real time.How can I achieve this for stream of 3d point.
Here I should be able to add new points to plot.
I tried this, its just plots series of data. How to update?
You could just plot in interactive mode, for example the following keeps adding new points,
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.ion()
plt.show()
x = np.linspace(0.,np.pi*4.,100)
ax.set_xlim([0.,13.])
ax.set_ylim([-1.5,1.5])
ax.set_zlim([-1.5,1.5])
for i in x:
ax.scatter(i, np.sin(i), np.cos(i))
print(i)
plt.pause(0.01)
UPDATE: added example of labelling
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.ion()
plt.show()
lsp = np.linspace(0.,np.pi*4.,100)
ax.set_xlim([0.,13.])
ax.set_ylim([-1.5,1.5])
ax.set_zlim([-1.5,1.5])
for i, x in enumerate(lsp):
y = np.sin(x)
z = np.cos(x)
ax.scatter(x, y, z)
if i%10 == 0:
ax.text(x, y, z, str(np.round(x,3))+", "
+str(np.round(y,3))+", "
+str(np.round(z,3)))
plt.pause(0.01)
How do I make a nice paraboloid in Matplotlib that looks like
All I can get is this,
where the top is not "cut off". I've tried just dropping all values of the Z array outside of the radius of the parabola at the top, but that gives very jagged edges. Can someone help me?
Here is my code:
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = (X**2 + Y**2)
ax.set_zlim(-10, 20)
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=4, cstride=4, linewidth=0.5, cmap=cm.summer)
plt.show()
For future reference, I had a thought to parametrize the surface in cylindrical coordinates, and it looks exactly how I want it:
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = T = np.arange(0, 2*pi, 0.01)
r, T = np.meshgrid(r, T)
#Parametrise it
X = r*np.cos(T)
Y = r*np.sin(T)
Z = r**2
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=10, cstride=10, linewidth=0.5, cmap=cm.summer)
plt.show()
I guess it makes sense: when working with a cylindrical object, use cylindrical coordinates!
Manual data clipping
One approach I've seen that works is to manually clip the data; e.g. your example would be updated to
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = (X**2 + Y**2)
ax.set_zlim(-10, 20)
for i in range(len(X)):
for j in range(len(Y)):
if (Z[j,i] < -10) or (Z[j,i] > 20):
Z[j,i] = NaN
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=4, cstride=4, linewidth=0.5, cmap=cm.summer)
plt.show()
Note
This can be done concisely for this case using
Z[Z>20] = NaN
Resulting in
I am using matplotlib for doing this
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
plt.show()
Now this builds a graph that is horizontal in the 3d space. How do I make the graph vertical so that it faces the user?
What I want to do is build multiple such vertical graphs that are separated by some distance and are facing the user.
bp's answer might work fine, but there's a much simpler way.
Your current graph is 'flat' on the z-axis, which is why it's horizontal. You want it to be vertical, which means that you want it to be 'flat' on the y-axis. This involves the tiniest modification to your code:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
# put 0s on the y-axis, and put the y axis on the z-axis
ax.plot(xs=x, ys=[0]*len(x), zs=y, zdir='z', label='ys=0, zdir=z')
plt.show()
Then you can easily have multiple such graphs by using different values for the ys parameter (for example, ys=[2]*len(x) instead would put the graph slightly behind).
Mayavi, in particular the mlab module, provides powerful 3D plotting that will work on large and or complex data, and should be easy to use on numpy arrays.
You can set the view angle of the 3d plot with the view_init() function. The example below is for version 1.1 of matplotlib.
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [6,3,6,9,12,24]
y = [3,5,78,12,23,56]
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
ax.view_init(90, -90)
plt.show()
According to the documentation you want to use the ax.plot_surface(x,y,z) method. More information and chart types here.
The following should work:
x = [1,2,3]
y = [4,5,6]
z = [7,8,9]
data = zip(x,y,z)
#map data on the plane
X, Y = numpy.meshgrid(arange(0, max(x), 1), arange(0, max(y), 1))
Z = numpy.zeros((len(Y), len(X)), 'Float32')
for x_,y_,z_ in data:
Z[x_, y_] = z_ #this should work, but only because x and y are integers
#and arange was done with a step of 1, starting from 0
fig = p.figure()
ax = p3.Axes3D(fig)
ax.plot_surface(X, Y, Z)