Search code examples
pythonpython-2.7numpymayavi

ZeroDivisionError: float division by zero in a code for Surface plot


I have got this code to generate a surface plot. But it gives a zero division error. I am not able to figure out what is wrong. Thank you.

import pylab, csv
import numpy
from mayavi.mlab import *

def getData(fileName):
    try:
        data = csv.reader(open(fileName,'rb'))
    except:
        print 'File not found'
    else:
        data = [[float(row[0]), float(row[1]),float(row[2])] for row in data]
        x = [row[0] for row in data]
        y = [row[1] for row in data]
        z = [row[2] for row in data]
    return (x, y, z)

def plotData(fileName):
    xVals, yVals, zVals = getData(fileName)
    xVals = pylab.array(xVals)   
    yVals = pylab.array(yVals)
    zVals = (pylab.array(zVals)*10**3)
    x, y = numpy.mgrid[-0.5:0.5:0.001, -0.5:0.5:0.001]  
    s = surf(x, y, zVals)
    return s

plotData('data')   

Solution

  • If I have understood the code correctly, there is a problem with zVals in mayavi.mlab.surf.

    According to the documentation of the function, s is the elevation matrix, a 2D array, where indices along the first array axis represent x locations, and indices along the second array axis represent y locations. Your file reader seems to return a 1D vector instead of an array.

    However, this may not be the most difficult problem. Your file seems to contain triplets of x, y, and z coordinates. You can use mayavi.mlab.surf only if your x and y coordinates in the file form a regular square grid. If this is the case, then you just have to recover that grid and form nice 2D arrays of all three parts. If the points are in the file in a known order, it is easy, otherwise it is rather tricky.

    Maybe you would want to start with mayavi.mlab.points3d(xVals, yVals, zVals). That will give you an overall impression of your data. (Or if already know more about your data, you might give us a hint by editing your question and adding more information!)


    Just to give you an idea of probably slightly pythonic style of writing this, your code is rewritten (and surf replaced) in the following:

    import mayavi.mlab as ml
    import numpy
    
    def plot_data(filename):
        data = numpy.loadtxt(filename)
        xvals = data[:,0]
        yvals = data[:,1]
        zvals = data[:,2] * 1000.
        return ml.points3d(x, y, z)
    
    plot_data('data')   
    

    (Essential changes: the use of numpy.loadtxt, get rid of pylab namespace here, no import *, no CamelCase variable or function names. For more information, see PEP 8.)


    If you only need to see the shape of the surface, and the data in the file is ordered row-by-row and with the same number of data points in each row (i.e. fixed number of columns), then you may use:

    import mayavi.mlab as ml
    import numpy
    importt matplotlib.pyplot as plt
    
    # whatever you have as the number of points per row
    columns = 13
    
    data = numpy.loadtxt(filename)
    
    # draw the data points into a XY plane to check that they really for a rectangular grid:
    plt.plot(data[:,0], data[:,1])
    
    # draw the surface
    zvals = data[:,2].reshape(-1,columns)
    ml.surf(zvals, warp_scale='auto')
    

    As you can see, this code allows you to check that your values really are in the right kind of grid. It does not check that they are in the correct order, but at least you can see they form a nice grid. Also, you have to input the number of columns manually. The keyword warp_scale takes care of the surface scaling so that it should look reasonable.