5

I want to plot some 3D+time points. For each timestep I have 2 set of named points (before and after treatment) and I want to use a slider (like here) to move in time. And if it's possible, I would like to add their name (labeling) near each point to recognize them (we cannot color text so I choose to add the names near the points). I'm a beginner, it's not simple for me and I'm really blocked on that problem. I don't know if my strategy is possible with 3D+time data in python.

I have 2 dictionary initialdata and finaldata where the keys correspond to timestep. I coded a function named plotting(initialdata, finaldata, t, plot_title = t, name, fuse) where t is the timestep (integer), plot_title is a string and fuse is a boolean (TRUE=initialdata and finaldata plotted in the same plot ; FALSE=they are plotted in 2 different subplot). name is a dictionary (keys correspond to time) with the corresponding name of each points. And that is my code :

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from pylab import *
from matplotlib.widgets import Slider, Button, RadioButtons

def plotting(before, after, time, title = '', name=[] , fuse = False, verbose = False) :
    if verbose :
        print "before : ", before
        print "after : ", after
    xb = before[time][0]
    yb = before[time][1]
    zb = before[time][2]
    xa = after[time][0]
    ya = after[time][1]
    za = after[time][2]
    titb = "before",title
    tita = "after",title
    fig = plt.figure(figsize=plt.figaspect(0.5))
    if fuse:
        fig.subplots_adjust(hspace=0.1)
        ax = fig.add_subplot(1, 2, 1, projection = '3d')
        ax.scatter(xb, yb, zb, s=len(before), c = 'r', marker = 'o')
        ax.set_xlabel('X')
        ax.set_ylabel('Y')
        ax.set_zlabel('Z')
        ax2 = fig.add_subplot(1, 2, 2, projection = '3d')
        ax2.scatter(xa, ya, za, s = len(after),c = 'b', marker = '^')
        ax.set_ylim([0,1000])
        ax2.set_xlabel('X')
        ax2.set_ylabel('Y')
        ax2.set_zlabel('Z')
        ax2.relim()
        ax2.autoscale_view(True,True,True)
        if len(name)>0:
            ax.text(xb, yb, zb, name[time])
            ax2.text(xa, ya, za, name[time])
    else:
        ax = fig.add_subplot(1, 2, 1, projection = '3d')
        ax.scatter(xb, yb, zb, s=len(before), c = 'r', marker = 'o')
        ax.scatter(xa, ya, za, s = len(after),c = 'b', marker = '^')
        ax.set_xlabel('X')
        ax.set_ylabel('Y')
        ax.set_zlabel('Z')
        if len(name)>0:
            ax.text(xb, yb, zb, name[time])
            ax.text(xa, ya, za, name[time])
        ax.set_autoscaley_on(False)
        ax.set_ylim([0,1000])
    plt.show()
    return 0

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d') #ax =fig.gca(projection='3d')

initialdata={1: [(1, 1, 1), (1, 2, 3), (2, 3, 4), (2, 2, 2), (2, 3, 4), (3, 4, 5)], 2: [(2, 2, 2), (2, 3, 4), (3, 4, 5), (3, 3, 3), (3, 4, 5)]}
finaldata={1: [(2, 2, 2), (2, 3, 4), (3, 4, 5), (3, 3, 3), (3, 4, 5), (4, 5, 6)], 2: [(3, 3, 3), (3, 4, 5), (4, 5, 6), (4, 4, 4), (4, 5, 6)]}
corresp = {1: ["a", "b", "c", "d", "e", "f"], 2: ["a", "c", "d", "e", "f", "g"]}
time=1
stime = Slider(ax, 'Time', 1, 60, valinit=time)
plotting(initialdata, finaldata, time, title=time, name=corresp)
stime.on_changed(update)
def update(val):
    time = stime.val
    plotting(initialdata, finaldata, time, title=time, name=corresp)
draw()

If I just try to plot one timestep without slider (by calling plotting() only), it plot that plotting(initial and I think it's ok... but it returns :

>>> plotting(initialdata, finaldata, 1, title=1, name=corresp)
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/figure.py", line 1159, in draw
    func(*args)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 293, in draw
    Axes.draw(self, renderer)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axes/_base.py", line 2324, in draw
     a.draw(renderer)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 85, in draw
     if dx==0. and dy==0.:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
0

And I would like to have the slider with my plot but this line doesn't work:

>>>stime = Slider(ax, 'Time', 1, 60, valinit=time)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/widgets.py", line 376, in __init__ horizontalalignment='right')
TypeError: text() takes at least 5 arguments (4 given)

but I have 5 arguments (ax and time are defined) so I don't understand why it doesn't work ! I searched in the matplotlib.widgets documentation whether I could understand the parameter of the Slider class, but I don't understand: they describe other parameters (vline? poly?) ; label is defined twice.

So what can I do ? Can you help me ?

Community
  • 1
  • 1
EaudeRoche
  • 207
  • 4
  • 19

0 Answers0