TheJD
TheJD

Reputation: 3

Matplotlib RuntimeWarning displaying a 3D plot

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.

Upvotes: 0

Views: 336

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339300

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

Upvotes: 1

Related Questions