0

I have a script which analyses a dataset and then outputs xyz data. In order to understand the distribution of the data, I want to visualize it in a 3d plot. As I have no experience what so ever with using matplotlib, I just copied the code from here and expected it to work with my text file which looks like this:

-0.9 -0.9 483
-0.9 -0.7 224
-0.9 -0.5 156
-0.9 -0.3 153
-0.9 -0.1 174
-0.9 0.1 268
-0.9 0.3 95
-0.9 0.5 59
-0.9 0.7 50
-0.9 0.9 199
-0.7 -0.9 917
-0.7 -0.7 244
-0.7 -0.5 208
-0.7 -0.3 148
-0.7 -0.1 139
-0.7 0.1 98
-0.7 0.3 52
-0.7 0.5 56
-0.7 0.7 60
-0.7 0.9 221
...

However, once I start the script, I get the following error which leads to the colorbar being displayed incorrectly:

Warning (from warnings module):
   File "C:\Program Files\Python35\lib\site-packages\matplotlib\colors.py", line 496
     cbook._putmask(xa, xa < 0.0, -1)
RuntimeWarning: invalid value encountered in less

Furthermore, the plot has these triangles on its edges. I'm not sure whether they are a consequence of the above mentioned error as well. This is the output: enter image description here

Here's my code:

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')

data = np.genfromtxt('plot.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]

xi = np.linspace(-1, 1)
yi = np.linspace(-1, 1)

X, Y = np.meshgrid(xi, yi)
Z = griddata(x, y, z, xi, yi, interp='linear')

surf = ax.plot_surface(X, Y, Z, rstride=5, cstride=5, cmap=cm.jet,
                   linewidth=1, antialiased=True)

ax.set_zlim3d(np.min(Z), np.max(Z))

fig.colorbar(surf)

plt.show()

EDIT 1: I edited the source code to print xa before the offending line, which outputs:

[  nan   nan   nan   nan   nan   nan   nan   nan   nan   nan   nan  256.
256.  256.  256.  256.  256.  256.  256.   nan   nan  256.  256.  256.
256.  256.  256.  256.  256.   nan   nan  256.  256.  256.  256.  256.
256.  256.  256.   nan   nan  256.  256.  256.  256.  256.  256.  256.
256.   nan   nan  256.  256.  256.  256.  256.  256.  256.  256.   nan
nan  256.  256.  256.  256.  256.  256.  256.  256.   nan   nan  256.
256.  256.  256.  256.  256.  256.  256.   nan   nan  256.  256.  256.
256.  256.  256.  256.  256.   nan   nan   nan   nan   nan   nan   nan
nan   nan   nan   nan]

So I clearly have some NaN values here, but I'm not sure where they come from.

4
  • This is a warning, not an error, hence you do get a plot out. It's really hard to know what's going on without a minimal reproducible example of the issue, i.e. we do not have your data. Best try to generate some data within the code to reproduce the issue. Commented Oct 20, 2017 at 8:11
  • If you go to the source code and put print(xa) before the offending line, you'll see the array contains nan values and that's because your Z contains nan values. Commented Oct 20, 2017 at 8:17
  • @ImportanceOfBeingErnest Thank you for your fast response and for editing my post. I did provide you with my data. The link above contains all the xyz coordinates I have. Commented Oct 20, 2017 at 8:24
  • @Reti43 Thank you for your hint. I edited my question accordingly! Commented Oct 20, 2017 at 8:32

1 Answer 1

1

The problem is that griddata cannot produce data for the edges of the grid. This is circumvented internally by masking the output array. However, for a masked array, a comparison xa < 0, which is needed to determine the colors, is not possible.

The solution here would be to exclude the edges from plotting.

ax.plot_surface(X[1:-1,1:-1], Y[1:-1,1:-1], Z[1:-1,1:-1])

Complete example:

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')

data = np.genfromtxt('plot.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]

xi = np.linspace(-1, 1)
yi = np.linspace(-1, 1)

X, Y = np.meshgrid(xi, yi)
Z = griddata(x, y, z, xi, yi, interp='linear')

surf = ax.plot_surface(X[1:-1,1:-1], Y[1:-1,1:-1], Z[1:-1,1:-1], 
                       rstride=5, cstride=5, cmap=cm.jet,
                       linewidth=1, antialiased=True)

ax.set_zlim3d(np.min(Z), np.max(Z))

fig.colorbar(surf)

plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

While griddata produces masked arrays for data outside your range, plot_surface doesn't support that yet. The function is located in the file site-packages\mpl_toolkits\mplot3d\axes3d.py and they have a todo note for supporting this. At the moment they just do X, Y, Z = np.broadcast(X, Y, Z), which destroys any masking and your nan values are exposed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.