Okay, apologies for this question but I'm pulling my hair out here.
I have a data structure loaded in python in the form:
[(1,0,#),(1,1,#),(1,2,#),(1,3,#),(2,0,#),(2,1,#) ... (26,3,#)]
with # being a different number each time that I wish to represent on the z-axis. You can see that x and y are always integers.
Plotting a scatter graph is simple:
x,y,z = zip(*data)
fig = plt.figure()
ax = fig.gca(projection = '3d')
surface = ax.scatter(x, y, z)
plt.show()
But when it comes to surfaces, I can see two methods:
1) Call ax.plot_trisurf(), which should work with 1D arrays similar to ax.scatter() and apparently works here, but for me gives me an error:
"AttributeError: Axes3D subplot object has not attribute 'plot_trisurf'"
This error also appears if I use the example source code at:
http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots, suggesting it's something wrong with my installation - my Matplotlib version is 1.1.1rc,. This error does not appear if, for example, ax.plot_surface() is called, nor ax.scatter().
2) Use meshgrid() or griddata() in combination with ax.plot_surface() - in either case, after two days' of pouring over the documentation and examples, I still don't understand how to correctly use these in my case, particularly when it comes to generating the values for Z.
Any help would be much appreciated.
To address your first question (1) I believe you need to import Axes3D from the mplot3d library, even if you're not directly calling it. Maybe try adding
from mpl_toolkits.mplot3d import Axes3D
before your main code (this line triggered a memory while reading the tutorial).
As for (2), X, Y and Z need to be matrix (2d array) type objects. This can get confusing, but you may consider an example:
# two arrays - one for each axis
x = np.arange(-5, 5, 0.25)
y = np.arange(-5, 5, 0.25)
# create a mesh / matrix like object from the arrays
X, Y = np.meshgrid(x, y)
# create Z values - also in a mesh like shape
Z = np.sin(np.sqrt(X**2 + Y**2))
# plot!
surface = ax.plot_surface(X, Y, Z)
Here is an example of how could you extract your z-values from data
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
data = [(j,i,i**2 + j) for j in range(1,27) for i in range(4)]
print data
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 4, 1)
Y = np.arange(1, 27, 1)
X, Y = np.meshgrid(X, Y)
print X.shape
print Y.shape
Z = np.array([z for _,_,z in data]).reshape(26,4)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=True)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
Related
I am using mplot3d from the mpl_toolkits library. When displaying the 3D surface on the figure I'm realized the axis were not positioned as I wished they would.
Let me show, I have added to the following screenshot the position of each axis:
Is there a way to change the position of the axes in order to get this result:
Here's the working code:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
ax = Axes3D(plt.figure())
def f(x,y) :
return -x**2 - y**2
X = np.arange(-1, 1, 0.02)
Y = np.arange(-1, 1, 0.02)
X, Y = np.meshgrid(X, Y)
Z = f(X, Y)
ax.plot_surface(X, Y, Z, alpha=0.5)
# Hide axes ticks
ax.set_xticks([-1,1])
ax.set_yticks([-1,1])
ax.set_zticks([-2,0])
ax.set_yticklabels([-1,1],rotation=-15, va='center', ha='right')
plt.show()
I have tried using xaxis.set_ticks_position('left') statement, but it doesn't work.
No documented methods, but with some hacking ideas from https://stackoverflow.com/a/15048653/1149007 you can.
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = ax = fig.add_subplot(111, projection='3d')
ax.view_init(30, 30)
def f(x,y) :
return -x**2 - y**2
X = np.arange(-1, 1, 0.02)
Y = np.arange(-1, 1, 0.02)
X, Y = np.meshgrid(X, Y)
Z = f(X, Y)
ax.plot_surface(X, Y, Z, alpha=0.5)
# Hide axes ticks
ax.set_xticks([-1,1])
ax.set_yticks([-1,1])
ax.set_zticks([-2,0])
ax.xaxis._axinfo['juggled'] = (0,0,0)
ax.yaxis._axinfo['juggled'] = (1,1,1)
ax.zaxis._axinfo['juggled'] = (2,2,2)
plt.show()
I can no idea of the meaning of the third number in triples. If set zeros nothing changes in the figure. So should look in the code for further tuning.
You can also look at related question Changing position of vertical (z) axis of 3D plot (Matplotlib)? with low level hacking of _PLANES property.
Something changed, code blow doesn't work, all axis hide...
ax.xaxis._axinfo['juggled'] = (0,0,0)
ax.yaxis._axinfo['juggled'] = (1,1,1)
ax.zaxis._axinfo['juggled'] = (2,2,2)
I suggest using the plot function to create a graph
I am not really sure if this is possible to do, but essentially I have a list of data corresponding to x, y and z coordinates.
Below image shows the result when I plot these points using a scatter graph (which I created using Python pyplot library).
My question is, is there any way of plotting the graph of a plane that passes through all of these points instead of plotting them as single points?
When I searched online all I found was resources telling me how to find equation of plane passing though 3 points but as you can see I have many points.
Any help will be appreciated.
Let's say that to have your plot you use this code
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
ax.scatter(x, y, z)
plt.show()
and let's say that you know nrows, ncols, the number of rows (y) and columns (x) of your base grid.
If these assumptions are correct, then you can use this code to plot a surface connecting the points
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
ax.plot_surface(*(v.reshape(nrows, ncols) for v in (x, y, z)))
plt.xlabel('x') ; plt.ylabel('y')
plt.show()
or, if you want something fancier,
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'),
layout='constrained')
surf = ax.plot_surface(*(v.reshape(nrows, ncols) for v in(x, y, z)),
cmap='Blues_r', ec='gray', lw=0.2)
plt.xlabel('x') ; plt.ylabel('y')
plt.colorbar(surf)
plt.show()
The prelude to my code, if you want to check my results, is
import numpy as np
import matplotlib.pyplot as plt
nrows, ncols = 63, 126
x = np.linspace(0, 12.5, ncols)
y = np.linspace(-6.2, 6.2, nrows)
X, Y = np.meshgrid(x, y)
x, y = (V.flatten() for V in (X, Y))
z = np.sin(x)-np.cos(y)
fig, ax = ...
...
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
I want to create some plots of the farfield of electromagnetic scattering processes.
To do this, I calculated values θ, φ and r. The coordinates θ and φ create a regular grid on the unitsphere so I can use plot_Surface (found here) with conversion to cartesian coordinates.
My problem is now, that I need a way to color the surface with respect to the radius r and not height z, which seems to be the default.
Is there a way, to change this dependency?
I don't know how you're getting on, so maybe you've solved it. But, based on the link from Paul's comment, you could do something like this. We pass the color values we want using the facecolor argument of plot_surface.
(I've modified the surface3d demo from the matplotlib docs)
EDIT: As Stefan noted in his comment, my answer can be simplified to:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
xlen = len(X)
Y = np.arange(-5, 5, 0.25)
ylen = len(Y)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
maxR = np.amax(R)
Z = np.sin(R)
# Note that the R values must still be normalized.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.jet(R/maxR),
linewidth=0)
plt.show()
And (the end of) my needlessly complicated original version, using the same code as above though omitting the matplotlib.cm import,
# We will store (R, G, B, alpha)
colorshape = R.shape + (4,)
colors = np.empty( colorshape )
for y in range(ylen):
for x in range(xlen):
# Normalize the radial value.
# 'jet' could be any of the built-in colormaps (or your own).
colors[x, y] = plt.cm.jet(R[x, y] / maxR )
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,
linewidth=0)
plt.show()
I want to plot red, blue and green colors on the three axis and an array which stores the value corresoding to each combination of color in python2.7....when i run my program either becomes unresponsive for 24 hours or it gives me memory error. Here is my code:
import pylab
import math
from itertools import product
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
N=[]
p=np.zeros((256,256,256))
S=[]
fig=plt.figure()
ax=fig.gca(projection='3d')
X=np.arange(0,256,1) #for one of the features either red, blue or green
Y=np.arange(0,256,1)
X,Y = np.meshgrid(X,Y)
R=np.sqrt(X**2 + Y**2)
Z=R/np.sqrt(2)
N=p.flatten();
N=(p[i,j,k] for k in Z)
surf=ax.plot_surface(X,Y,Z, rstride=1, cstride=1,
facecolors=cm.jet(N),
linewidth=0, antialiased=False, shade=False)
plt.show()
Please help. I have read the previous posts, and have used them, still I am getting memory error. Here p is a containing values of combinations of red, green and blue. For simplicity I have initialized it to zero...it is giving the following error..colset.append(fcolors[rs][cs])
IndexError: index out of bounds
First, your program is slow because you're doing a lot of unnecessary work building N. You're building a 70 MB list a few bytes at a time (256*256*256=16,777,216 appends!). A better (faster, memory efficient) way to build p is to use numpy's array broadcasting, and then reuse p to make N:
import numpy as np
a = np.arange(256)
p = a[:,np.newaxis,np.newaxis] * a[np.newaxis,:,np.newaxis] * a[np.newaxis,np.newaxis,:]
N = p.flatten()
Second and more importantly, you're not using plot_surface() correctly. According to the docs, X, Y and Z should be 2D arrays. X and Y lay down a 2D grid and Z provides the "height" for each point on that 2D grid. If you want to manually set the facecolor, it should also be a 2D array. You should look at the example in the docs for a working example.
EDIT:
I'm not sure what your plot is intended to look like, so lets walk through the MPL demo.
Make the necessary imports and create an axis object (yours does this correctly):
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
Next, make an X/Y grid and corresponding Z. In your program, X, Y and Z are 1D. They describe a line in 3D space, not a surface.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y) # <-- returns a 2D grid from initial 1D arrays
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
Lets first plot the simplest thing possible. No colors, default anti-aliasing, lines, etc.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
plt.show()
Now add a colors. Note that the color comes from the Z component.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
plt.show()
Now manually control the colors (MPL inspiration).
colortuple = ('y', 'k') # only use two colors: yellow and black
xlen, ylen = X.shape # get length of
colors = np.empty(X.shape, dtype=str) # make a 2D array of strings
for i in range(xlen):
for j in range(ylen):
index = (i + j) % 2 # alternating 0's and 1's
colors[i,j] = colortuple[index]
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
facecolors=colors)
If you want to color based on some other metric, you can create your own colormap. There are many answered questions on how to do that.
Edit 2:
Colors can also be specified as RGB sequences. For something like your red on X, green on Y description you could do this:
xlen, ylen = X.shape
colors = np.zeros((xlen,ylen,3))
jspan = np.linspace(0., 1., ylen)
ispan = np.linspace(0., 1., xlen)
for i in range(xlen):
colors[i,:,0] = jspan
for j in range(ylen):
colors[:,j,1] = ispan
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,)