I've basically just copied the example code found on the Matplotlib website, but I replaced their radii and angles with simple arange arrays.
I've tried different array functions and I can't seem to figure out anything.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from Equation import Expression
x = np.arange(0,100,0.01)
y = np.arange(0,100,0.01)
x2 = np.append(0,x.flatten())
y2 = np.append(0,y.flatten())
z = x2 + y2
print(z)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(x, y, z, linewidth=0.2, antialiased=True)
plt.show()
I'm just trying to make a graph of z = x + y but I'm getting a confusing error.
"RuntimeError: Error in qhull Delaunay triangulation calculation: singular input data (exitcode=2); use python verbose option (-v) to see original qhull error."
Edit: I've also tried it without calling flatten() but I get the same result though.
The error you are getting is because your z is not a surface but a line. You need to use at least 3 points that would define a plane. One option could be to use np.meshgrid to create your surface for plotting and then flatten everything to insert into the function. Try going back to some example code here. Note you may also want to change your resolution depending on the detail of your surface.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,100,1)
y = np.arange(0,100,1)
x2 = np.append(0,x.flatten())
y2 = np.append(0,y.flatten())
x2,y2 = np.meshgrid(x2,y2) #This is what you were missing
z = x2 + y2
fig = plt.figure(figsize=(12,12))
ax = fig.gca(projection='3d')
ax.plot_trisurf(x2.flatten(), y2.flatten(), z.flatten(), linewidth=0.2, antialiased=True) #flatten all the arrays here
plt.show()
Related
I'm trying to graph a 3d mesh surface with matplotlib and constrain the limits of the graph. The X and Y axes are correctly constrained, but there is overflow in the Z-Axis.
What am I missing? Here's my code:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits import mplot3d
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,10))
x = np.linspace(-6,6,100)
y = np.linspace(-6,6,100)
X,Y = np.meshgrid(x,y)
def f(x,y):
return x**2 + 3*y
Z = f(X,Y)
ax = plt.axes(projection = '3d')
ax.plot_surface(X,Y,Z,cmap='viridis')
ax.title.set_text("z=x**2+3y")
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_zlim3d(zmin=-3,zmax=5)
ax.set_xlim3d(xmin=-6,xmax=6)
ax.set_ylim3d(ymin=-6,ymax=6)
plt.show()
The graph:
Edit:
When I add clipping/min/max to the Z values, the graph is a little better, but it sets z values outside the bounds to the bounds themselves. Both of the following suggestions do this. Perhaps it's because I'm on a mac?
z_tmp = np.maximum(np.minimum(5,Z),-3)
z_temp = np.clip(Z, -3, 5, None)
Your data is outside the axis boundaries. Try rotate the view and you will notice.
z = x**2 + 3*y
If you want to only show a defined area of the data you could add a max() min() limitation on the Z data to exclude the data outside your wanted limitations.
Z = f(X,Y)
z_tmp = np.maximum(np.minimum(5,Z),-3)
ax = plt.axes(projection = '3d')
ax.plot_surface(X,Y,z_tmp,cmap='viridis')
I'm not sure the matplotlib behaves as it should in your default case.
I am trying to shade the area before the point of intersection of the two curves produced by this example code:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,100,10)
y1 = [0,2,4,6,8,5,4,3,2,1]
y2 = [0,1,3,5,6,8,9,12,13,14]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(t_list,y1,linestyle='-')
ax.plot(t_list,y2,linestyle='--')
plt.show()
Simply using:
ax.fill_between(x,y1,y2,where=y1>=y2,color='grey',alpha='0.5')
Does no work and gives the following error: "ValueError: Argument dimensions are incompatible"
I tried to convert the lists into arrays:
z1 = np.array(y1)
z2 = np.array(y2)
Then:
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey',alpha='0.5')
Not the entire area was shaded.
I know I have to find the point of intersection between the two curves by interpolating but have not seen a simple way to do it.
You are completely right, you need to interpolate. And that is ludicrously complicated, as you need to add the interpolate=True keyword argument to the call to fill_between.
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey', interpolate=True)
Complete code to reproduce:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,100,10)
y1 = [0,2,4,6,8,5,4,3,2,1]
y2 = [0,1,3,5,6,8,9,12,13,14]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y1,linestyle='-')
ax.plot(x,y2,linestyle='--')
z1 = np.array(y1)
z2 = np.array(y2)
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey',alpha=0.5, interpolate=True)
plt.show()
I have a list like below -
array1 = [[1,2,3,0.56],[12,5,30,0.23],[10,12,17,89.65]]
This represents co-ordinates- [[x1,y1,z1,c1],[x2,y2,z2,c2],[x3,y3,z3,c3]].
I used 4D plot with 4th dimension[c1,c2,c3] being the color. I am stuck at plotting. I would like to have a color for c1 at co-ordinates [x1,y1,z1] and similarly to other co-ordinates.
I used the below methods -
import matplotlib.pyplot as plt
import numpy as np
1) for p in range(len(array1)-1):
x = np.append([array1[p][0]], array1[p+1][0])
y = np.append([array1[p][1]], array1[p+1][1])
z = np.append([array1[p][2]], array1[p+1][2])
c = np.append([array1[p][3]], array1[p+1][3])
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(x,y,z,c=c,cmap = cmap)
plt.show()
The problem in method 1 is, its not plotting all the elements of the list. I guess there is a mistake in executing append. I am not getting any errors but its just not plotting every data.
2) fig = plt.figure()
ax = fig.gca(projection='3d')
for p in range(len(array1)-1):
ax.scatter(array1[p][0],array1[p][1],array1[p][2],array1[p][3],cmap =
cmap)
plt.show()
So in method 2, I tried to plot iteratively but its giving me 'float object unsubscriptable' error.
So can somebody tell me where I am going wrong. Or is there any other method to do this ?
This is one way of doing it by converting your list to array which allows you to slice all the elements directly as x, y, z and color coordinates.
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
new_array = = np.array(array1)
ax.scatter(new_array[:,0],new_array[:,1],new_array[:,2], c=new_array[:,3], cmap=cm.RdBu, s=100)
I'm trying to learn Python through a tutorial on youtube and I'm having some difficulies working with 3D graphs. Long stories short, I continuously get (if
Z.ndim != 2:
AttributeError: 'list' object has no attribute 'ndim')
error while trying to launch this simple program:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
chart = fig.add_subplot(1,1,1,projection = '3d')
X,Y,Z = [1,2,3,4,5,6,7,8],[2,5,3,8,9,5,6,1],[3,6,2,7,5,4,5,6]
chart.plot_wireframe(X,Y,Z)
plt.show()
I know that it is related to the Axes3.plot_wireframe() method but Could anyone explain to me what's happening.
I walked around this problem by doing two things.
import numpy as np
making the z-axis a multidimensional array
#My 3d graph
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
figure = plt.figure()
axis = figure.add_subplot(111, projection = '3d')
x = [1,2,3,4,5,6,7,8,9,10]
y = [5,6,7,8,2,5,6,3,7,2]
z = np.array([[1,2,6,3,2,7,3,3,7,2],[1,2,6,3,2,7,3,3,7,2]])
axis.plot_wireframe(x, y, z)
axis.set_xlabel('x-axis')
axis.set_ylabel('y-axis')
axis.set_zlabel('z-axis')
plt.show()
Take special note of the z variable. If z is not multidimensional, it will throw an error.
Hope it solves your problem
Running your code with either Python 2.7.10 or Python 3.6.0, with matplotlib version 2.0.2, yields the same image with no error:
This is not a wireframe though, and a simple ax.plot(X, Y, Z) would have generated it. As DavidG and ImportanceOfBeingErnest cleverly mentioned, it makes no sense to pass 1D lists to the wireframe function, as X, Y and Z should be two-dimensional.
The following code (an example taken from the matplotlib official documentation) shows exactly how the parameters of the plot_wireframe function should be (using numpy arrays):
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
'''
def get_test_data(delta=0.05):
from matplotlib.mlab import bivariate_normal
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2 - Z1
X = X * 10
Y = Y * 10
Z = Z * 500
return X, Y, Z
'''
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x, y, z = axes3d.get_test_data(0.05)
ax.plot_wireframe(x,y,z, rstride=2, cstride=2)
plt.show()
The output image is a true wireframe:
Printing x.shape, for instance, yields you (120, 120), showing that the array is two-dimensional and have 120 positions in the first dimension and 120 positions in the second one.
I had the exact problem (example from video not working though exactly copied). Without looking into the source code I'm assuming a reality check was added to matplotlib 2.1.0 that NOW stops 1D arrays from being used in plot_wireframe. Changing that method call to simply "plot" did indeed fix the problem.
The command
ax.plot_wireframe(x,y,z, rstride=2, cstride=2)
is creating the problems with the latest versions.
Try using:
ax.plot(x,y,z)
This will definitely solve your issues.
Python has been known for being inconsistent with the older libraries.
I am getting this image as the output:
This is the 3d Image I am getting
Teacher in class gave this formula
w = x**2 + y**2 - z**2
and showed its 3d graphic in class seen below. How do I plot this using Matplotlib (minus the intersecting plane)? I guess first a specific value for w needs to be selected, for example 10, otherwise 3d plotting would not be possible. Then should I convert to polar coordinates because of the z**2 in the formula? I tried this and failed. Any help would be appreciated. Also, does this shape have a name?
Got it. Found some good stuff here, and following the formulas presented, I have the Python code below.
http://msenux.redwoods.edu/Math4Textbook/Plotting/ParametricSurfaces.pdf
from __future__ import division
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=plt.figaspect(1)) # Square figure
ax = fig.add_subplot(111, projection='3d')
r=1;
u=np.linspace(-2,2,200);
v=np.linspace(0,2*np.pi,60);
[u,v]=np.meshgrid(u,v);
a = 1
b = 1
c = 1
x = a*np.cosh(u)*np.cos(v)
y = b*np.cosh(u)*np.sin(v)
z = c*np.sinh(u)
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.show()