I have this file : https://pastebin.com/WK6K97jv (columns are respectively x,y,z=f(x,y)).
I would like to plot using matplotlib (pyplot) unfortunately I never have to deal with 3d plot and I've tried to do this :
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
fig = plt.figure()
ax = fig.gca(projection='3d')
X=np.genfromtxt('./jpdf1/jpdf1.000533048.dat',usecols=(0,))
Y=np.genfromtxt('./jpdf1/jpdf1.000533048.dat',usecols=(1,))
X, Y = np.meshgrid(X, Y)
Z=np.genfromtxt('./jpdf1/jpdf1.000533048.dat',usecols=(2,))
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
but interpreter back me this :
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/homebrew/lib/python3.9/site-packages/matplotlib/_api/deprecation.py", line 431, in wrapper
return func(*inner_args, **inner_kwargs)
File "/opt/homebrew/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 1658, in plot_surface
raise ValueError("Argument Z must be 2-dimensional.")
ValueError: Argument Z must be 2-dimensional.
check the Z.shape whether equal to X.shape or Y.shape.
Z.shape == X.shape
then give your a example.
# import package
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
fig = plt.figure()
ax = fig.gca(projection='3d')
# generate x and y data
X = np.arange(20) # shape: 20
Y = np.arange(30) # shape:30
X, Y = np.meshgrid(X, Y) # convert x y data shape to new shape
print(X.shape) # (20,30)
print(Y.shape) # (20, 30)
Z= np.cos(X**2 + Y**2) # shape =(20,30)
printt(Z.shape) # (20, 30)
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
I have extracted nodal fields from my geodynamic simulation, but I'm stuck on visualizing it. Here I take rock density rho [kg/m3] as an example. The data are represented on the nodal points of a 3D rectangular grid, with a resolution of 10 * 3 * 10 km.
The lengths of my coordinates are X * Y * Z = 213 * 69 * 133 nodes, where X and Z are horizontal and Y is the vertical coordinate. The dimensions of rho are 69 * 213 * 133 (so y, x, z)
Ideally, I would like to draw some sort of box in (x,z,y) space and assign a color to it according to the value of rho. However, for now I'm fine with creating a color-coded scatter plot at the nodes. I've looked in many places, e.g. the matplotlib.mpl_toolkits.Axes3D documentation, and here, and almost all of them say something like
img = ax.scatter(x, z, y, c=rho, cmap=plt.hot())
Or versions using ax.plot_surface, or ax.plot_trisurf, and those explicitly require X, Y, Z to be of the same length.
ax.scatter also only seems to work when x, y, z and rho have the same length, which seems unnecessary to me... However I try, I get errors like (on calling the scatter command):
File "/usr/lib/python3/dist-packages/mpl_toolkits/mplot3d/axes3d.py", line 2354, in scatter
xs, ys, zs = np.broadcast_arrays(
File "<__array_function__ internals>", line 5, in broadcast_arrays
File "/usr/lib/python3/dist-packages/numpy/lib/stride_tricks.py", line 264, in broadcast_arrays
shape = _broadcast_shape(*args)
File "/usr/lib/python3/dist-packages/numpy/lib/stride_tricks.py", line 191, in _broadcast_shape
b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I looked up what that means, and supposedly it means that the dimensions don't match. But I checked in a debugger, and the dimensions are correct.
I tried flattening rho (same result) and I tried looping over each node and plotting each point separately (sample down below)
rho, x, y, z = read_data('/path/to/my/data')
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
for i in range(len(x)):
for j in range(len(z)):
for k in range(len(y)):
ax.scatter(x[i], z[j], y[k], c=ronew[k, i, j], cmap='hot')
cbar = plt.colorbar(orientation='horizontal')
cbar.set_label('Density [kg/m3]')
plt.xlabel("X [km]")
plt.ylabel("Z [km]")
plt.zlabel("Depth [km]")
plt.show()
I imagine I'm not the only one who needs to make these "4D" figures. Therefore, any help would be very much appreciated! To make helping easier, here's a sample data that produces the above copied error:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
x = np.arange(0, 10)
y = np.arange(0, 6)
z = np.arange(0, 20)
rho = np.random.randint(1000, 3500, (10, 6, 20))
fig = plt.figure()
print(x.shape, y.shape, z.shape, rho.shape)
ax = fig.add_subplot(projection='3d')
ax.scatter(x, y, z, c=rho, cmap='hot')
plt.show()
Okay, so thanks to #JohanC 's comment I found out that the 4D scatter is not possible with matplotlib version 3.1.4 (the reason is beyond me). After upgrading matplotlib to 3.4.3 I had no problems after calling xx, yy, zz = np.meshgrid(x, y, z) and plotting like
ax.scatter(xx, zz, -yy, c=rho, cmap='hot')
I produced the following figure from the test code:
And this one from the real data file
I was trying to plot a 3D diagram with manual input data (x,y,z) using ax.plot_surface. Even though I used a similar code I found online, I still got some errors.
"Warning (from warnings module):
File "D:\Program Files (x86)\Python\Python36\lib\site-packages\numpy\core\_methods.py", line 29
return umr_minimum(a, axis, None, out, keepdims)
RuntimeWarning: invalid value encountered in reduce
Warning (from warnings module):
File "D:\Program Files (x86)\Python\Python36\lib\site-packages\numpy\core\_methods.py", line 26
return umr_maximum(a, axis, None, out, keepdims)
RuntimeWarning: invalid value encountered in reduce
Warning (from warnings module):
File "D:\Program Files (x86)\Python\Python36\lib\site-packages\matplotlib\colors.py", line 489
np.copyto(xa, -1, where=xa < 0.0)
RuntimeWarning: invalid value encountered in less"
Even with this errors, the diagram could be plotted. But it's all black. And somehow, the colorbar does not match the z values.
Can anyone help me with this problem? I appreciate your help.
This is the code I used (the exact code is shown below):
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
import numpy as np
import scipy.interpolate
from matplotlib.ticker import LinearLocator, FormatStrFormatter
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [1043.797,621.694,203.275,-213.783,-627.143,-1045.474,-1045.474,-628.403,-213.783,0.42,203.278,621.697,1043.801,1042.545,621.701,203.282,0.426,-213.778,-628.397,-1045.467,-0.834,1043.804,621.701,203.292,0.434,-213.77,-628.393,-1045.462,-1045.464,-628.395,-213.772,-0.829,203.29,621.707,1043.812,1043.807,621.706,203.287,-213.775,-628.398,-1045.466]
y = [-1210.936,-1211.146,-1210.931,-1210.819,-1210.916,-1210.916,-727.082,-726.768,-726.776,-726.883,-726.887,-727.101,-726.68,-242.741,-243.059,-242.846,-242.841,-242.732,-242.723,-243.037,19.801,241.133,241.025,241.248,241.148,241.154,241.167,241.07,725.216,725.208,724.565,725.401,724.976,724.97,724.975,1209.226,1209.324,1209.328,1209.338,1209.559,1209.254]
z = [3753.086,4054.802,4101.778,4064.706,3844.414,3614.887,4156.525,4184.521,4284.536,4269.797,4273.816,4298.024,4264.16,4224.935,4188.664,4200.863,4210.243,4164.851,4143.223,4148.073,3980.13,4094.025,4203.862,4260.099,4238.935,4233.248,4186.161,4072.293,4021.05,4311.022,4351.636,4359.61,4385.24,4382.892,4169.055,3927.979,4226.974,4237.096,4180.779,4082.677,3739.785]
x=np.asarray(x)
y=np.asarray(y)
N = 100
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]),
method='cubic')
xi, yi = np.meshgrid(xi,yi)
surf = ax.plot_surface(xi, yi, zi, cmap=plt.cm.hot)
plt.show()
Due to the interpolation on the grid, the outmost points of the resulting array are nan (i.e. first and last column & first and last row). While nan values can be ignored for plotting, they are unfortunately not for producing the colorization. In order to be able to use a colormap, an array without nan values should be provided (this is strictly only true for 3D plots).
While there are in general several options like replacing values and masking, here the easiest is to leave out the rows and columns from plotting. I.e. instead of ax.plot_surface(xi, yi, zi, cmap="hot") you can use
ax.plot_surface(xi[1:-1,1:-1], yi[1:-1,1:-1], zi[1:-1,1:-1], cmap="hot")
Complete example:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [1043.797,621.694,203.275,-213.783,-627.143,-1045.474,-1045.474,-628.403,-213.783,0.42,203.278,621.697,1043.801,1042.545,621.701,203.282,0.426,-213.778,-628.397,-1045.467,-0.834,1043.804,621.701,203.292,0.434,-213.77,-628.393,-1045.462,-1045.464,-628.395,-213.772,-0.829,203.29,621.707,1043.812,1043.807,621.706,203.287,-213.775,-628.398,-1045.466]
y = [-1210.936,-1211.146,-1210.931,-1210.819,-1210.916,-1210.916,-727.082,-726.768,-726.776,-726.883,-726.887,-727.101,-726.68,-242.741,-243.059,-242.846,-242.841,-242.732,-242.723,-243.037,19.801,241.133,241.025,241.248,241.148,241.154,241.167,241.07,725.216,725.208,724.565,725.401,724.976,724.97,724.975,1209.226,1209.324,1209.328,1209.338,1209.559,1209.254]
z = [3753.086,4054.802,4101.778,4064.706,3844.414,3614.887,4156.525,4184.521,4284.536,4269.797,4273.816,4298.024,4264.16,4224.935,4188.664,4200.863,4210.243,4164.851,4143.223,4148.073,3980.13,4094.025,4203.862,4260.099,4238.935,4233.248,4186.161,4072.293,4021.05,4311.022,4351.636,4359.61,4385.24,4382.892,4169.055,3927.979,4226.974,4237.096,4180.779,4082.677,3739.785]
x=np.asarray(x)
y=np.asarray(y)
N = 100
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]),
method='cubic')
xi, yi = np.meshgrid(xi,yi)
surf = ax.plot_surface(xi[1:-1,1:-1], yi[1:-1,1:-1], zi[1:-1,1:-1], cmap=plt.cm.hot)
plt.show()
I'm trying to make a 3d plot from a list of lists of values. All the sublists have the same number of values.
I tried this: Plot a 3d surface from a 'list of lists' using matplotlib , but I get the error:
ValueError: shape mismatch: objects cannot be broadcast to a single shap
Here is how to reproduce:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
list_of_lists = [[1,2,3,4,1,2,3,4,1,2,3,4],[2,3,5,9,2,3,5,9,2,3,5,9],[5,9,8,1,5,9,8,1,5,9,8,1],[1,2,3,4,1,2,3,4,1,2,3,4],[2,3,5,9,2,3,5,9,2,3,5,9],[5,9,8,1,5,9,8,1,5,9,8,1]]
data = np.array(list_of_lists)
length = data.shape[0]
width = data.shape[1]
x, y = np.meshgrid(np.arange(length), np.arange(width))
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
ax.plot_surface(x, y, data)
plt.show()
Thank you
Due to default cartesian indexing of meshgrid output (see docs for more info) your data has shape of (6, 12), but x and y have shapes of (12, 6). The easiest way to solve the problem is to transpose data array:
ax.plot_surface(x, y, data.T)
Or you can apply matrix indexing notation to meshgrid output:
x, y = np.meshgrid(np.arange(length), np.arange(width), indexing='ij')
I am running simulations with 2 variables: P and Q.
Both P and Q vary from [0.2, 0.4, 0.6, 0.8]
Each combination of P and Q produce an output which I call NB_Means.
nb_means is produced by running the simulator with P=0.2 and varying the Q with [.2,.4,.6,.8], after which I move on to the next P (.4) and repeat the same process.
EX: so below in nb_means: p=.2&q=.2 -> 32 and p=.2&q=.4 -> 159 ... and so on
I am attempting to plot the wire frame as so:
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
x=[.2,.2,.2,.2,.4,.4,.4,.4,.6,.6,.6,.6,.8,.8,.8,.8]
y=[.2,.4,.6,.8,.2,.4,.6,.8,.2,.4,.6,.8,.2,.4,.6,.8]
nb_means = [32, 159, 216, 327, 206, 282, 295, 225, 308, 252, 226, 229, 301, 276, 262, 273]
fig = plt.figure()
ax = plt.axes(projection='3d')
X,Y = np.meshgrid(x,y)
ax.set_title('Name Based Routing')
ax.set_xlabel('Prob of Request')
ax.set_ylabel('Prob of Publish')
ax.set_zlabel('RTT')
ax.plot_wireframe(X, Y, nb_means, rstride=10, cstride=10)
plt.show()
However, as you see in the output above... I expected the wireplot to increase along the Q axis. But it does not.
Am I setting up my x and y incorrectly?
The X, Y, and nb_means are all the problem. They should all be 2D arrays (your nb_means is currently a 1D list). You also don't need to make X and Y using meshgrid, all you need to do is reshape them all:
X = np.reshape(x, (4,4))
Y = np.reshape(y, (4,4))
nb2 = np.reshape(nb_means, (4,4))
...
ax.plot_wireframe(X, Y, nb2)
You may also not really want that rstride=10 and cstride=10.