annotating many points with text in mayavi using m

2019-04-28 13:12发布

问题:

I'm trying to annotate points plotted with the points3d() function using mayavi.mlab. Each point is associated with a label which I would like to plot next to the points using the text3d() function. Plotting the points is fast, however the mlab.text3d() function does not seem to accept arrays of coordinates, so I have to loop over the points and plot the text individually, which is very slow:

        for i in xrange(0, self.n_labels):
            self.mlab_data.append(
                mlab.points3d( pX[self.labels == self.u_labels[i], 0],
                               pX[self.labels == self.u_labels[i], 1],
                               pX[self.labels == self.u_labels[i], 2],
                               color=self.colours[i],
                               opacity=1,
                               scale_mode="none",
                               scale_factor=sf ) )

            idcs, = np.where(self.labels == self.u_labels[i])
            for n in idcs.flatten():
                mlab.text3d( pX[n, 0],
                             pX[n, 1],
                             pX[n, 2],
                             "%d" % self.u_labels[i],
                             color=self.colours[i],
                             opacity=1,
                             scale=sf )

Any ideas how I could speed this up? Also, is it possible to add a legend (as for instance in matplotlib), I couldn't find anything in the docs.

Thanks,

Patrick

回答1:

The way you are doing it above will render the scene every time you plot a point or text. This is slow. You can disable the scene rendering, do the plotting and then render the scene by figure.scene.disable_render = True/False:

    import scipy
    from mayavi import mlab

    X = 100 * scipy.rand(100, 3)
    figure = mlab.figure('myfig')
    figure.scene.disable_render = True # Super duper trick
    mlab.points3d(X[:,0], X[:,1], X[:,2], scale_factor=0.4)
    for i, x in enumerate(X):
        mlab.text3d(x[0], x[1], x[2], str(i), scale=(2, 2, 2))
    figure.scene.disable_render = False # Super duper trick

I use this trick and others in Figure class in morphic Viewer https://github.com/duanemalcolm/morphic/blob/master/morphic/viewer.py

Another good trick in the code is to reuse existing objects, i.e., if you've plotted the text already, don't replot them, just update their position and text attributes. This means saving the mlab object. You can see how I do this in morphic.Viewer.