0

what would be the best recommendation in order to move the 6 blue balls around the 3D field a) with a pygtk and threading matplot for the plot window? (menue in pygtk where the new position is given manually and the balls would move after a "Click Go") b) or something else? It seems that matplot is slow: 4s after starting the attached python script, the plot windows open and everything appear. Moving later manually the window (rotation) is very slow too (it is mandatory, I have access to that manual rotation function of the plot window in order to observe the position of the balls in the 3D field). Perhaps another library or programm should be used? For the reason 6 additional balls (light grey) must be added, it will become probably slow. The 3D rendering dont has to be good (just a bit non transparent 3D). Any recommendation is welcome before I go too far in that pygtk and matplotlib direction. The programm is for hobby sport and will help beginners to know where to have their position in a field and how to move (3D.. NOT 2D)

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import matplotlib.axes as axs
import numpy as np
import math
from pylab import figure

# parameter in m
#swimminpool_width
s_w = 10
#swimmingpool_length
s_l = 18
#swimmingpool_depth
s_d = 4
#exchange lane width
el_w = 3
# ball radius
b_r = 0.53 / (2 * math.pi)

if __name__ == '__main__':

    # basket at the swimmingpool bottom in the middle
    x_basket1 = s_w / 2
    y_basket1 = 0.24
    # basket at the swimmingpool bottom in the middle
    x_basket2 = s_w / 2
    y_basket2 = s_l - 0.24
    #
    fig = plt.figure()
    ax1 = fig.add_subplot (111,projection='3d')

    # field
    xG = [0,10,10,0,0, 0,10,10,10,10,10, 0, 0,0, 0,10]
    yG = [0, 0, 0,0,0,18,18, 0, 0,18,18,18,18,0,18,18]
    zG = [0, 0, 4,4,0, 0, 0, 0, 4, 4, 0, 0, 4,4, 4, 4]
    ax1.plot_wireframe (xG,yG,zG,colors= (0,0,1,1))  # blue line game area

    # exchange area
    xW = [10,13,13,10,10,10,13,13,13,13,13,10,10,10,10,13]
    yW = [0,  0, 0, 0, 0,18,18, 0, 0,18,18,18,18, 0,18,18]
    zW = [0,  0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 4, 4, 4, 4]
    ax1.plot_wireframe (xW,yW,zW,colors= (0,1,1,1))  # light blue line exchange area
#
    ax1.set_xlabel('Wide')
    ax1.set_ylabel('Length')
    ax1.set_zlabel('Depth')
#
    # Make data for sphere 80cm radius = player1
    # pos Player 1
    Pos_xP1 = 1
    Pos_yP1 = 1
    Pos_zP1 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP1 = Pos_xP1+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP1 = Pos_yP1+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP1 = Pos_zP1+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP1, yP1, zP1,color= (0,0,1,1))
    #mark it
    i=1
    ax1.text(Pos_xP1, Pos_yP1, Pos_zP1, '%s' % (str(i)), size=20,color='k')
#
    # Make data for sphere 80cm radius = player2
    # pos Player 2 (use later lists)?
    Pos_xP2 = 2.5
    Pos_yP2 = 1
    Pos_zP2 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP2 = Pos_xP2+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP2 = Pos_yP2+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP2 = Pos_zP2+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP2, yP2, zP2,color= (0,0,1,1))
    #mark it
    i=2
    ax1.text(Pos_xP2, Pos_yP2, Pos_zP2, '%s' % (str(i)), size=20,color='k')
#
    # Make data for sphere 80cm radius = player3
    # pos Player 3
    Pos_xP3 = 4
    Pos_yP3 = 1
    Pos_zP3 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP3 = Pos_xP3+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP3 = Pos_yP3+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP3 = Pos_zP3+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP3, yP3, zP3,color= (0,0,1,1))
    #mark it
    i=3
    ax1.text(Pos_xP3, Pos_yP3, Pos_zP3, '%s' % (str(i)), size=20,color='k')
#
    # Make data for sphere 80cm radius = player4
    # pos Player 4
    Pos_xP4 = 5.5
    Pos_yP4 = 1
    Pos_zP4 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP4 = Pos_xP4+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP4 = Pos_yP4+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP4 = Pos_zP4+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP4, yP4, zP4,color= (0,0,1,1))
    #mark it
    i=4
    ax1.text(Pos_xP4, Pos_yP4, Pos_zP4, '%s' % (str(i)), size=20,color='k')
#
    # Make data for sphere 80cm radius = player5
    # pos Player 5
    Pos_xP5 = 7
    Pos_yP5 = 1
    Pos_zP5 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP5 = Pos_xP5+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP5 = Pos_yP5+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP5 = Pos_zP5+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP5, yP5, zP5,color= (0,0,1,1))
    #mark it
    i=5
    ax1.text(Pos_xP5, Pos_yP5, Pos_zP5, '%s' % (str(i)), size=20,color='k')
#
    # Make data for sphere 80cm radius = player6
    #  pos Player 6
    Pos_xP6 = 8.5
    Pos_yP6 = 1
    Pos_zP6 = 4
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP6 = Pos_xP6+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP6 = Pos_yP6+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP6 = Pos_zP6+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(xP6, yP6, zP6,color= (0,0,1,1))
    #mark it
    i=6
    ax1.text(Pos_xP6, Pos_yP6, Pos_zP6, '%s' % (str(i)), size=20,color='k')
#
    #
    # Make data for sphere ball
    posx_ball = 5
    posy_ball = 9
    posz_ball = b_r
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    x_ball = posx_ball + b_r * np.outer(np.cos(u), np.sin(v))
    y_ball = posy_ball + b_r * np.outer(np.sin(u), np.sin(v))
    z_ball = posz_ball + b_r * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    ax1.plot_surface(x_ball, y_ball, z_ball, color=(1, 0, 0, 1))
#
#use a factor for having y = x in factor
    ax1.set_aspect(aspect=0.222)
#
# define the basket1
    t = np.linspace(0, np.pi * 2, 16)
    #bottom
    ax1.plot(x_basket1+0.24*np.cos(t), y_basket1+0.24*np.sin(t), 0,  linewidth=1, color='black')
    ax1.plot(x_basket1+0.16*np.cos(t), y_basket1+0.16*np.sin(t), 0,  linewidth=1, color='black')
    #top
    ax1.plot(x_basket1+0.24*np.cos(t), y_basket1+0.24*np.sin(t), 0.45,  linewidth=1, color='black')
    # side bars
    A=0
    while A < 16:
        xBar = [x_basket1+ 0.16 * math.sin(A*22.5*np.pi/180),x_basket1+ 0.24 * math.sin(A*22.5*np.pi/180)]
        yBar = [y_basket1+ 0.16 * math.cos(A*22.5*np.pi/180),y_basket1+ 0.24 * math.cos(A*22.5*np.pi/180)]
        zBar = [0,0.45]
        ax1.plot(xBar,yBar,zBar,color='black')
        A = A+1

# define the basket2
    t = np.linspace(0, np.pi * 2, 16)
    # bottom
    ax1.plot(x_basket2 + 0.24 * np.cos(t), y_basket2 + 0.24 * np.sin(t), 0, linewidth=1, color='black')
    ax1.plot(x_basket2 + 0.16 * np.cos(t), y_basket2 + 0.16 * np.sin(t), 0, linewidth=1, color='black')
    # top
    ax1.plot(x_basket2 + 0.24 * np.cos(t), y_basket2 + 0.24 * np.sin(t), 0.45, linewidth=1, color='black')
    # side bars
    A = 0
    while A < 16:
        xBar = [x_basket2 + 0.16 * math.sin(A * 22.5 * np.pi / 180),x_basket2 + 0.24 * math.sin(A * 22.5 * np.pi / 180)]
        yBar = [y_basket2 + 0.16 * math.cos(A * 22.5 * np.pi / 180),y_basket2 + 0.24 * math.cos(A * 22.5 * np.pi / 180)]
        zBar = [0, 0.45]
        ax1.plot(xBar, yBar, zBar, color='black')
        A = A + 1

    #
    plt.show()
Ed Smith
  • 12,716
  • 2
  • 43
  • 55
floppy_molly
  • 175
  • 1
  • 10

2 Answers2

1

I'm not sure why this has been downvoted, seems a reasonable question. However, matplotlib is not intended to be a solution for fast plotting (see this answer) and has limited support for 3D, so certainly consider another library for this.

That said, if you are only using 6 balls then I think you can make this work. I'd suggest cleaning up your code using functions for repeated code, for example defining,

def draw_ball(x, y, z, label="", color=(0,0,1,1)):
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP1 = x+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP1 = y+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP1 = z+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))

    # Plot the surface
    b = ax1.plot_surface(xP1, yP1, zP1, color= color)

    #mark it
    t = ax1.text(x, y, z, '%s' % label, size=20, color='k')

    return b, t

would allow you to set everything up with just,

players = []
for i in range(6):
    players.append(draw_ball(1+i*1.5, 1, 4, label=str(i+1)))

That said, you'll find that drawing spheres with plot surface/text is too slow, instead I'd recommend using a scatter plot, with some transparency, and changing the data each time as follows,

#Instead, get all positions and plot as a single scatter collection
pos = []
for i in range(6):
    pos.append([1+i*1.5, 1, 4])
#Define numpy array which is faster to work with
pos = np.array(pos)
s = ax1.scatter(pos[:,0], pos[:,1], pos[:,2], s=100, alpha = 0.5)

where pos is a 6 by 3 array for all players ball locations. This can then be updated as follows, from this answer, when pos changes,

s._offsets3d = juggle_axes(pos[:,0], pos[:,1], pos[:,2], 'z')

It should be more efficient to update the whole collection (6 players by 3) all in one go. Adding annotation can be done following the excellent example by @Luchko.

To give you an idea how this all works together, try running the following code,

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import matplotlib.axes as axs
import numpy as np
import math

from mpl_toolkits.mplot3d.proj3d import proj_transform
from matplotlib.text import Annotation

#based on https://stackoverflow.com/questions/10374930/matplotlib-annotating-a-3d-scatter-plot#34139293
class Annotation3D(Annotation):
    '''Annotate the point xyz with text s'''

    def __init__(self, s, xyz, *args, **kwargs):
        Annotation.__init__(self,s, xy=(0,0), *args, **kwargs)
        self._verts3d = xyz        

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.xy=(xs,ys)
        Annotation.draw(self, renderer)


def annotate3D(ax, s, *args, **kwargs):
    '''add anotation text s to to Axes3d ax'''

    tag = Annotation3D(s, *args, **kwargs)
    ax.add_artist(tag)


def draw_ball(x, y, z, label="", color=(0,0,1,1)):
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    xP1 = x+ 0.4 * np.outer(np.cos(u), np.sin(v))
    yP1 = y+ 0.4 * np.outer(np.sin(u), np.sin(v))
    zP1 = z+ 0.4 * np.outer(np.ones(np.size(u)), np.cos(v))

    # Plot the surface
    b = ax1.plot_surface(xP1, yP1, zP1, color= color)

    #mark it
    t = ax1.text(x, y, z, '%s' % label, size=20, color='k')

    return b, t

def draw_basket(x, y, z, h, color='black'):
    # define the basket1
    t = np.linspace(0, np.pi * 2, 16)
    #bottom
    ax1.plot(x+0.24*np.cos(t), y+0.24*np.sin(t), z,  linewidth=1, color=color)
    ax1.plot(x+0.16*np.cos(t), y+0.16*np.sin(t), z,  linewidth=1, color=color)
    #top
    ax1.plot(x+0.24*np.cos(t), y+0.24*np.sin(t), z+h,  linewidth=1, color=color)
    # side bars
    A=0
    while A < 16:
        xBar = [x+ 0.16 * math.sin(A*22.5*np.pi/180),x+ 0.24 * math.sin(A*22.5*np.pi/180)]
        yBar = [y+ 0.16 * math.cos(A*22.5*np.pi/180),y+ 0.24 * math.cos(A*22.5*np.pi/180)]
        zBar = [0,0.45]
        ax1.plot(xBar, yBar, zBar, color=color)
        A = A+1

# parameter in m
#swimminpool_width
s_w = 10
#swimmingpool_length
s_l = 18
#swimmingpool_depth
s_d = 4
#exchange lane width
el_w = 3
# ball radius
b_r = 0.53 / (2 * math.pi)

if __name__ == '__main__':

    # basket at the swimmingpool bottom in the middle
    x_basket1 = s_w / 2
    y_basket1 = 0.24
    # basket at the swimmingpool bottom in the middle
    x_basket2 = s_w / 2
    y_basket2 = s_l - 0.24

    fig = plt.figure()
    ax1 = fig.add_subplot(111,projection='3d')

    # field
    xG = [0,10,10,0,0, 0,10,10,10,10,10, 0, 0,0, 0,10]
    yG = [0, 0, 0,0,0,18,18, 0, 0,18,18,18,18,0,18,18]
    zG = [0, 0, 4,4,0, 0, 0, 0, 4, 4, 0, 0, 4,4, 4, 4]
    ax1.plot_wireframe (xG,yG,zG,colors= (0,0,1,1))  # blue line game area

    # exchange area
    xW = [10,13,13,10,10,10,13,13,13,13,13,10,10,10,10,13]
    yW = [0,  0, 0, 0, 0,18,18, 0, 0,18,18,18,18, 0,18,18]
    zW = [0,  0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 4, 4, 4, 4]
    ax1.plot_wireframe (xW,yW,zW,colors= (0,1,1,1))  # light blue line exchange area

    ax1.set_xlabel('Wide')
    ax1.set_ylabel('Length')
    ax1.set_zlabel('Depth')

    #use a factor for having y = x in factor
    ax1.set_aspect(aspect=0.222)

    # Make data for sphere ball
    draw_ball(8.5, 1, b_r, label="")

    # define the basket1
    draw_basket(x_basket1, y_basket1, 0., 0.45)

    # define the basket2
    draw_basket(x_basket2, y_basket2, 0., 0.45)

    #Instead, get all positions and plot as a single scatter collection
    pos = []
    for i in range(6):
        pos.append([1+i*1.5, 1, 4])
    #Define numpy array which is faster to work with
    pos = np.array(pos)
    s = ax1.scatter(pos[:,0], pos[:,1], pos[:,2], s=100, alpha = 0.5)

    #Add labels
    for j, xyz_ in enumerate(pos): 
        annotate3D(ax1, s=str(j), xyz=xyz_, fontsize=10, xytext=(-3,3),
                   textcoords='offset points', ha='right',va='bottom')   

    #Use interactive mode for quick animation
    plt.ion()
    plt.show()

    # Do 100 steps and add random change to positions
    for step in range(100):
        for i in range(pos.shape[0]):
            pos[i,0] += 0.1*np.random.randn(1)
            pos[i,1] += 0.1*np.random.randn(1)
            pos[i,2] += 0.1*np.random.randn(1)

        s._offsets3d = pos[:,0], pos[:,1], pos[:,2]
        plt.pause(0.01)

this appears to allow quick rotation and plotting, at least for me,

enter image description here

Ed Smith
  • 12,716
  • 2
  • 43
  • 55
  • Big big improvement in speed. A scatter point is a very good solution (and enough as representation). I will have to increase the size of the scatter points: when I put the windows in full screen, it has to become bigger. It means a link between zooming and scatter point size should be defined, or if this is not possible, for the reason I will use it mostly in full screen mode, I will have to find how to make the scatters bigger anyway. – floppy_molly Jan 08 '18 at 18:32
  • the points appear blue in the video. In the code above on my pc it appear grey. I will search now how to achieve the different colors of the scatter "dark blue" and "light grey" – floppy_molly Jan 08 '18 at 18:40
  • I try to understand the "0.1*np.random.randn(1)". Its not a numeral? – floppy_molly Jan 11 '18 at 20:07
  • s._offsets3d = juggle_axes(pos[:,0], pos[:,1], pos[:,2], 'z') seems to turn the axis with the same value and come back to the original position at each loop. I dont understand how it happens. – floppy_molly Jan 11 '18 at 20:13
  • (I try to make a movement of the scatter points by allowing manual positioning of the axis with the mouse) – floppy_molly Jan 11 '18 at 20:15
  • @floppy_molly the term `0.1*np.random.randn(1)` is just a single normally distributed random number, just there for the example to show points moving but you'd do this based on the player inputs I assume. I'm not sure you need `juggle_axes`, the mouse rotation seems to look okay for me without it and makes no difference. I've deleted it. – Ed Smith Jan 12 '18 at 15:54
  • thanks. I updated the script. Now, 2 "balls" are moving (up to 12 balls will move later). But they stop when the axis are turned with the mouse. How to keep the movement/dynamic of the "balls" when somebody move the axis with the mouse? any indication about script change to keep the dynamic is welcome. – floppy_molly Jan 17 '18 at 19:32
  • This works okay for me (see gif above, balls keep moving during rotation), does this happend with code above? May be an issue with your matplotlib backend or caused by the "Click Go" user input . The ball positions/figure redraw is from the `step in range(100)` loop and the rotation is a user event, see https://matplotlib.org/users/event_handling.html so you'd need to see if this is interfering/stopping this loop. I'd post as a new question if you can't fix. – Ed Smith Jan 18 '18 at 09:59
  • my modified script above dont use random but target coordinate. it can be the source of difference. by using FuncAnimation similar to https://stackoverflow.com/questions/40890632/python-animated-3d-scatterplot-gets-slow then the "balls" dont stop moving when I rotate the axis with the mouse. it looks better. I dont know how to control the FuncAnimation for moving an object from A to B without repeating but the object stay at B; I will further search. I think, slowly and carefully, that thread is closed. – floppy_molly Jan 18 '18 at 20:57
0
#!/usr/bin/python3.5
"""
/* game uwr: field and basket design test module
 * Copyright (C) Creative Commons Alike V4.0
 * No warranty
 */
"""
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import juggle_axes
import matplotlib.axes as axs
import numpy as np
import math

from mpl_toolkits.mplot3d.proj3d import proj_transform
from matplotlib.text import Annotation

# parameter in m
#swimminpool_width
s_w = 10
#swimmingpool_length
s_l = 18
#swimmingpool_depth
s_d = 4
#exchange lane width
el_w = 3
# ball radius
b_r = 0.53 / (2 * math.pi)


# coordinate depth_pb1 player blue nb 1
# previous1 and previous2 is array pos_p1_b and array pos_p2_b
# current is array pos_b ..
# target is (from menue gtk) 1m length and 1m deeper

depth_pb1 = 2
length_pb1 = 2
side_pb1 = ((s_w/6)/2)+0*(s_w/6)
text_speed_pb1 = "low"

#based on https://stackoverflow.com/questions/10374930/matplotlib-annotating-a-3d-scatter-plot#34139293
class Annotation3D(Annotation):
    '''Annotate the point xyz with text s'''

    def __init__(self, s, xyz, *args, **kwargs):
        Annotation.__init__(self,s, xy=(0,0), *args, **kwargs)
        self._verts3d = xyz

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.xy=(xs,ys)
        Annotation.draw(self, renderer)

def annotate3D(ax, s, *args, **kwargs):
    '''add anotation text s to to Axes3d ax'''

    tag = Annotation3D(s, *args, **kwargs)
    ax.add_artist(tag)

def draw_basket(x, y, z, h, color='black'):
    # define the basket1
    t = np.linspace(0, np.pi * 2, 16)
    #bottom
    ax1.plot(x+0.24*np.cos(t), y+0.24*np.sin(t), z,  linewidth=1, color=color)
    ax1.plot(x+0.16*np.cos(t), y+0.16*np.sin(t), z,  linewidth=1, color=color)
    #top
    ax1.plot(x+0.24*np.cos(t), y+0.24*np.sin(t), z+h,  linewidth=1, color=color)
    # side bars
    A=0
    while A < 16:
        xBar = [x+ 0.16 * math.sin(A*22.5*np.pi/180),x+ 0.24 * math.sin(A*22.5*np.pi/180)]
        yBar = [y+ 0.16 * math.cos(A*22.5*np.pi/180),y+ 0.24 * math.cos(A*22.5*np.pi/180)]
        zBar = [0,0.45]
        ax1.plot(xBar, yBar, zBar, color=color)
        A = A+1

def draw_ball(x, y, z, label="", color=(1,0,0,1)):
    global b_r
    u = np.linspace(0, 2 * np.pi, 50)
    v = np.linspace(0, np.pi, 50)
    xP1 = x+ b_r * np.outer(np.cos(u), np.sin(v))
    yP1 = y+ b_r * np.outer(np.sin(u), np.sin(v))
    zP1 = z+ b_r * np.outer(np.ones(np.size(u)), np.cos(v))
    # Plot the surface
    b = ax1.plot_surface(xP1, yP1, zP1, color= color)
    #mark it
    t = ax1.text(x, y, z, '%s' % label, size=20, color='k')
#        return b, t

if __name__ == '__main__':

    # basket at the swimmingpool bottom in the middle
    x_basket1 = s_w / 2
    y_basket1 = 0.24
    # basket at the swimmingpool bottom in the middle
    x_basket2 = s_w / 2
    y_basket2 = s_l - 0.24

    fig = plt.figure()
    ax1 = fig.add_subplot(111,projection='3d')

    # field
    xG = [0,10,10,0,0, 0,10,10,10,10,10, 0, 0,0, 0,10]
    yG = [0, 0, 0,0,0,18,18, 0, 0,18,18,18,18,0,18,18]
    zG = [0, 0, 4,4,0, 0, 0, 0, 4, 4, 0, 0, 4,4, 4, 4]
    ax1.plot_wireframe (xG,yG,zG,colors= (0,0,1,1))  # blue line game area

    # exchange area
    xW = [10,13,13,10,10,10,13,13,13,13,13,10,10,10,10,13]
    yW = [0,  0, 0, 0, 0,18,18, 0, 0,18,18,18,18, 0,18,18]
    zW = [0,  0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 4, 4, 4, 4]
    ax1.plot_wireframe (xW,yW,zW,colors= (0,1,1,1))  # light blue line exchange area

    ax1.set_xlabel('Wide')
    ax1.set_ylabel('Length')
    ax1.set_zlabel('Water')

    # draw the 2 lines which show the depth
    xG1 = [0, 10]
    yG1 = [4, 4]
    zG1 = [0, 0]
    ax1.plot_wireframe(xG1, yG1, zG1, colors=(0, 0, 1, 1),linestyle=':')  # blue line
    xG2 = [0, 10]
    yG2 = [14, 14]
    zG2 = [0, 0]
    ax1.plot_wireframe(xG2, yG2, zG2, colors=(0, 0, 1, 1),linestyle=':')  # blue line
    #
    # put the axis fix
    ax1.set_xlim3d(0, 13)
    ax1.set_ylim3d(0, 18)
    ax1.set_zlim3d(0, 4)
    #
    # use a factor for having y = x in factor
    ax1.set_aspect(aspect=0.222)
    #
    # sphere red ball for playing
    draw_ball(5, 9, b_r, label="")
    #
    # define the basket1
    draw_basket(x_basket1, y_basket1, 0., 0.45)

    # define the basket2
    draw_basket(x_basket2, y_basket2, 0., 0.45)

    #get all positions and plot as a single scatter collection at all player position blue
    pos_b = []
    for i in range(6):
        # distribute the players at the side with the same distance
        # at game start
        pos_b.append([((s_w/6)/2)+i*(s_w/6),1, s_d])
    #Define numpy array which is faster to work with
    pos_b = np.array(pos_b)
    # s parameter below is the surface of the scatter point 100 is 80cm diam by non zooming
    # c blue
    p_b = ax1.scatter(pos_b[:,0], pos_b[:,1], pos_b[:,2], s=400, alpha = 0.5, c=(0, 0, 1, 1))

    #Add labels
    for j, xyz_ in enumerate(pos_b):
        annotate3D(ax1, s=str(j+1), xyz=xyz_, fontsize=10, xytext=(-3,3),
                   textcoords='offset points', ha='right',va='bottom')

    #
    #get all positions and plot as a single scatter collection at all player position white
    pos_w = []
    for i in range(6):
        # distribute the players at the side with the same distance
        # at game start
        pos_w.append([((s_w/6)/2)+i*(s_w/6), (s_l-1), s_d])
    #Define numpy array which is faster to work with
    pos_w = np.array(pos_w)
    # s parameter below is the surface of the scatter point 100 is 80cm diam by non zooming
    # c="lightgrey", alpha=0.5 half transparent
    p_w = ax1.scatter(pos_w[:,0], pos_w[:,1], pos_w[:,2], s=400, alpha = 0.5, c="darkgrey")

    #Add labels
    for j, xyz_ in enumerate(pos_w):
        annotate3D(ax1, s=str(j+1), xyz=xyz_, fontsize=10, xytext=(-3,3),
                   textcoords='offset points', ha='right',va='bottom')
#
#
    #Use interactive mode for quick animation
    plt.ion()
    plt.show()

# Linear move in 10 steps
    # Do 10 steps and add change to positions in homogenous speed along distance of each player
#    delta_pos_pb1_x = side_pb1 - pos_b[0,0]
#    delta_pos_pb1_y = length_pb1 - pos_b[0,1]
#    delta_pos_pb1_z = depth_pb1 - pos_b[0,2]
    delta_pos_pb1_x = 3
    delta_pos_pb1_y = 3
    delta_pos_pb1_z = -3

    delta_pos_pb2_x = 3
    delta_pos_pb2_y = 0.5
    delta_pos_pb2_z = -3.5

    for step in range(10):
        pos_b[0,0] += 0.1 * delta_pos_pb1_x
        pos_b[0,1] += 0.1 * delta_pos_pb1_y
        pos_b[0,2] += 0.1 * delta_pos_pb1_z

        pos_b[1, 0] += 0.1 * delta_pos_pb2_x
        pos_b[1, 1] += 0.1 * delta_pos_pb2_y
        pos_b[1, 2] += 0.1 * delta_pos_pb2_z

#        for i in range(pos_b.shape[0]):
#            pos_b[i,0]+= 0.01*delta_pos_pb1_x
#            pos_b[i,1]+= 0.01*delta_pos_pb1_y
#            pos_b[i,2]+= 0.01*delta_pos_pb1_z
#            plt.pause(1.0)
#            plt.draw()
#        s._offsets3d = juggle_axes(pos_b[:,0], pos_b[:,1], pos_b[:,2], 'z')
        p_b._offsets3d = pos_b[:, 0], pos_b[:, 1], pos_b[:, 2]
        plt.pause(0.001)
floppy_molly
  • 175
  • 1
  • 10
  • I create a ball with a scatter point p_ball = ax1.scatter(pos_ball_now[0], pos_ball_now[1], pos_ball_now[2], s=100, alpha = 0.5, c="red") but how to move it? p_ball._offsets3d = pos_ball_now[0],pos_ball_now[1],pos_ball_now[2] give errors. – floppy_molly Feb 27 '18 at 21:19