I am new to Python. I have been trying to plot a data file that contains 3 columns and 1024 data points. While running the code the following error arises:
Traceback (most recent call last):
File "plot-data.py", line 27, in <module>
linewidth=0, antialiased=False)
File "/home/ritajit/.local/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 1624, in plot_surface
X, Y, Z = np.broadcast_arrays(X, Y, Z)
File "/home/ritajit/.local/lib/python2.7/site-packages/numpy/lib/stride_tricks.py", line 249, in broadcast_arrays
shape = _broadcast_shape(*args)
File "/home/ritajit/.local/lib/python2.7/site-packages/numpy /lib/stride_tricks.py", line 184, in _broadcast_shape
b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape
My code looks like this
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.mlab import griddata
import matplotlib.cm as cm
from pylab import rcParams
rcParams['figure.figsize'] = 9, 9
## 3D surface_plot
fig = plt.figure()
axes = fig.add_subplot(111, projection='3d') #gca = get current axis
data = np.loadtxt('2D-data.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]
xi = np.unique(x)
yi = np.unique(y)
xv, yv = np.meshgrid(x,y)
Z = griddata(x, y, z, xi, yi, interp='linear')
# surface_plot with color grading and color bar
p = axes.plot_surface(xv,yv,Z, rstride=4, cstride=4, cmap=cm.RdBu,
linewidth=0, antialiased=False)
fig.colorbar(p, shrink=0.5)
axes.set_xlabel('$x$',fontsize=15)
axes.set_ylabel('$y$',fontsize=15)
axes.set_zlabel('$z$',fontsize=15)
plt.tight_layout()
fig.savefig("surface.pdf")
plt.show()
I am unable to work this through.
What wrong am I doing?
Is there any other way to plot 3d datafile?
A few lines from my data file:
1 2 1.30884
2 2 1.30925
3 2 1.30974
4 2 1.30841
5 2 1.30864
6 2 1.30795
The 1st,2nd,3rd columns are x,y,z respectively
Three main issues here:
You need to meshgrid the unique values, not the original ones
xi = np.unique(x)
yi = np.unique(y)
xv, yv = np.meshgrid(xi,yi)
You need to interpolate on the gridded values
griddata(x, y, z, xv, yv)
You need to plot Z, not z
p = axes.plot_surface(xv,yv,Z)
In total it looks like you could achieve pretty much the same by reshaping the data columns (but the small data excerpt is not enough to judge on this).
Last, matplotlib.mlab.griddata will be deprecated in the next version. As an alternative consider scipy.interpolate.griddata. Also have a look at the Contour plot of irregularly spaced data example.
Related
I am trying to plot a surface and a line which is passing through it. I want to have a plot where the portion of the line which is behind the surface, is hidden.
I tried this in matplotlib but the portion of the line behind the surface is also visible.
Line intersecting a surface
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
x = np.arange(0,10,1)
y = np.arange(0,10,1)
z = np.arange(0,10,1)
X, Y = np.meshgrid(x,y)
Z= np.ones((len(x),len(x)))*5
fig = plt.figure()
ax1 = fig.gca(projection='3d')
ax1.plot_surface(X, Y, Z, color='red', edgecolor='black')
ax1.plot(x,y,z,'-',color='black',linewidth=4)
plt.show()
In matplotlib, there is a concept of the zorder. Objects with a higher zorder are plotted in a layer on top of objects with a lower zorder, as per the docs. By default, the patch has a higher zorder than the line, which is why your red surface appears to block out the line. Here I have created a new set of coordinates for the background and foreground parts of the line, by selecting indices where z <= 5 or z >= 5 respectively. Then I plot these two sets of points separately, setting the zorder for all three - the surface and both of the lines.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
z = np.arange(0, 10, 1)
x_background = x[z <= 5]
y_background = y[z <= 5]
z_background = z[z <= 5]
x_foreground = x[z >= 5]
y_foreground = y[z >= 5]
z_foreground = z[z >= 5]
X, Y = np.meshgrid(x, y)
Z = np.ones((len(x), len(x))) * 5
fig = plt.figure()
ax1 = fig.gca(projection='3d')
ax1.plot_surface(X, Y, Z, color='red', edgecolor='black', zorder=1)
ax1.plot(
z_background, z_background, z_background, '-', color='black', linewidth=4,
zorder=2)
ax1.plot(
z_foreground, z_foreground, z_foreground, '-', color='black', linewidth=4,
zorder=3)
plt.show()
Hope this helps!
I am using matplotlib.pyplot to animate some array data. The data is in the form of an intensity map, so I have a mesh of x and y locations, and a value associated with those locations.
The difficulty is that I cannot simply update the intensity data because the x and y locations change as well.
For example, I can get something like this work, but it requires having an over-determined x and y grid first that will cover the entire range:
cax = ax.pcolormesh(x, y, G[:-1, :-1, 0],
vmin=-1, vmax=1, cmap='Blues')
fig.colorbar(cax)
def animate(i):
cax.set_array(G[:-1, :-1, i].flatten())
This works, but I end up with a fairly large intensity array filled mostly with zeros.
I have found an example here that allows the x and y values to be changed. Here is a modified MWE:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig2 = plt.figure()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
ims = []
for add in np.arange(15):
x = np.arange(-9+add, 10+add)
y = np.arange(-9+add, 10+add)
x, y = np.meshgrid(x, y)
ims.append((plt.pcolormesh(x, y, base + add, norm=plt.Normalize(0, 30)),))
im_ani = animation.ArtistAnimation(fig2, ims, interval=50, repeat_delay=3000,
blit=True)
plt.show()
The issue here is two-fold. First, I have about 3000 frames, so the list ims becomes unmanageable. Secondly, how can I get the data to clear between frames and not show every frame all at once? Perhaps there's a better way altogether?
Bonus: using a slider could be an alternative to an animation. I've used Slider on these types of data before, but only by initializing a huge x and y grid.
Thanks for the help! Apologies if I'm not using the proper tags.
I may misunderstand the problem here, but using a FuncAnimation seems more appropriate here.
With blitting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
def animate(i):
x = np.arange(-9+i, 10+i)
y = np.arange(-9+i, 10+i)
x, y = np.meshgrid(x, y)
pc = ax.pcolormesh(x, y, base + i, norm=plt.Normalize(0, 30))
return pc,
ax.axis([-9,30,-9,30])
im_ani = animation.FuncAnimation(fig, animate, frames=30, interval=50,
repeat_delay=3000, blit=True)
plt.show()
Without blitting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
store=[]
def animate(i):
x = np.arange(-9+i, 10+i)
y = np.arange(-9+i, 10+i)
x, y = np.meshgrid(x, y)
if store:
store[0].remove()
del store[0]
pc = ax.pcolormesh(x, y, base + i, norm=plt.Normalize(0, 30))
store.append(pc)
ax.axis([-9,30,-9,30])
im_ani = animation.FuncAnimation(fig, animate, frames=30, interval=50,
repeat_delay=3000)
plt.show()
I have a 3D data cube which I scatter plot using a loop. I want the scatter points to be the cube index, and the color of the scatter points to be the value. Below is code that yields all one color. How do I make the colors based on the value?
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
%matplotlib
# I have a 3D array of numbers of unknown shape containing unknown
# integer values within an unknown range.
# Here, I made this toy 3D array with shape 9,10,11 containing random
# integer values 0-10.
xyz = np.random.rand(9,10,111)*100//10
# Determine the shape of the the array
x_size = np.shape(xyz)[0]
y_size = np.shape(xyz)[1]
z_size = np.shape(xyz)[2]
# Scatter plot the array
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
for xi in range(x_size):
for yi in range(y_size):
for zi in range(z_size):
ax.scatter(xi, yi, zi, c=xyz[xi, yi, zi])
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# I have a 3D array of numbers of unknown shape containing unknown
# integer values within an unknown range.
# Here, I made this toy 3D array with shape 9,10,11 containing random
# integer values 0-10.
xyz = np.random.rand(9,10,111)*100//10
# Determine the shape of the the array
x_size = np.shape(xyz)[0]
y_size = np.shape(xyz)[1]
z_size = np.shape(xyz)[2]
# Scatter plot the array
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
xi, yi, zi = np.meshgrid(range(x_size), range(y_size), range(z_size))
ax.scatter(xi, yi, zi, c=xyz)
plt.show()
I am trying to create a 3d surface plot in matplotlib. the plot surface works fine using ax.plot_surface api. But I couldn't find a way to remove the padding surrounding the subplot. In fact, I don't need the outer axes that go from 0.0 to 1.0 at all. How can i remove the padding? I already tried many suggestions from stackoverflow like "ax.autoscale_view('tight')" and "fig.tight_layout()". autoscale_view don't change anything and fig.tight_layout() is not available in the matplotlib version i am using. For strict compatibility requirements i have to use a very old (Version 0.99) version of matplotlib. Any ideas ?
For completeness I have added a sample source code i am using:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize = (18,12))
rect = fig.add_subplot(2, 3, 2).get_position()
ax = Axes3D(fig, rect)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.view_init(azim=-90, elev=90)
ax.axis('off')
plt.show()
I am trying to follow a MATLAB example of meshgrid + interpolation. The example code is found HERE. On that site, I am going through the following example: Example – Displaying Nonuniform Data on a Surface.
Now, I would like to produce a similar plot in Python (Numpy + Matplotlib) to what is shown there in MATLAB. This is the plot that MATLAB produces:
I am having trouble with doing this in Python. Here is my code and my output in Python 2.7:
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,cmap=cm.jet)
Here is the result of my attempt at doing this with matplotlib and NumPy..
Could someone please help me recreate the MATLAB plot in matplotlib, as either a mesh or a surface plot?
So it seems that the major differences in the look have to do with the default number of lines plotted by matlab, which can be adjusted by increasing rstride and cstride. In terms of color, in order for the colormap to be scaled properly it is probably best in this case to set your limits, vmin and vmax because when automatically set, it will use the min and max of Z, but in this case, they are both nan, so you could use np.nanmin and np.nanmax.
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=5, cstride=5, cmap=cm.jet, vmin=np.nanmin(Z), vmax=np.nanmax(Z), shade=False)
scat = ax.scatter(x, y, z)
In matplotlib unfortunately I get some annoying overlapping/'clipping' problems, where Axes3d doesn't always properly determine the order in which object should be displayed.