0

a) in the script below, only 1 loop of the FuncAnimation is stored as video. How to make the video storing continuously the never ending Funcanimation? (it would stop anyway when I destroy the main window)

b) how to control such video (start/stop) from signals coming for example from a GUI made with PyGTK? The control would happens in parall to the never FuncAnimation (no stop of the funcanimation) Any suggestion is welcome.

UPDATE 1: by adding following code in "animate" of a "FuncAnimation" call, I create pictures which I will put together later in one video. By controlling the picture counting from a GUI, I can limit the size of the video, stop it, pause it.. Topic closed. By reading following it was solved How can I make a video from array of images in matplotlib?

video_page_iter = video_page_iter+1 # if video is on
plt.savefig("/home/family/Bilder" + "/file%03d.png" % video_page_iter)  # if video is on
#
if video_page_iter==100:   # or if command store video
    os.chdir("/home/family/Bilder")
    subprocess.call([
        'ffmpeg', '-framerate', '8', '-i', 'file%03d.png', '-r', '30', '-pix_fmt', 'yuv420p',
        'video_name.mp4'
    ])
    for file_name in glob.glob("*.png"):
        os.remove(file_name)
    video_page_iter = 0


import math
import sys
import gi
#import csv
#import pandas as pd
#
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk as gtk, Gdk as gdk, GLib, GObject as gobject
import string
import os
import subprocess
import glob
from datetime import datetime, timedelta
import time
import numpy as np
import matplotlib; matplotlib.use('Gtk3Agg')
    #('GTKCairo' dont work)
import matplotlib.animation as animation
from mpl_toolkits.mplot3d.proj3d import proj_transform
from matplotlib.text import Annotation
#from cairocffi import *
#from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas  # this work a bit
#from matplotlib.backends.backend_gtk3 import NavigationToolbar2GTK3 as NavigationToolbar
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas # this work full?
import matplotlib.pyplot as plt
#from multiprocessing import Process,Queue,Value
import multiprocessing as mp
#
#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(ax1, x, y, z, h, color='black'):
    '''add basket to the ax1 figure'''
    # define the basket
    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,h]
        ax1.plot(xBar, yBar, zBar, color=color)
        A = A+1

def draw_halfsphere (ax1, x, y, z, sph_radius, color=(0,0,1,1)):
    ''' add free distance surface to Axes3d ax1 '''
#        https://stackoverflow.com/questions/40460960/how-to-plot-a-sphere-when-we-are-given-a-central-point-and-a-radius-size
    u, v = np.mgrid[0:2 * np.pi:20j, 0:np.pi/2:10j]
    xP1 = x + sph_radius * np.cos(u) * np.sin(v)
    yP1 = y + sph_radius * np.sin(u) * np.sin(v)
    zP1 = z - sph_radius * np.cos(v)
    # Plot the surface
    halffreesphere = ax1.plot_wireframe(xP1, yP1, zP1, color=color, alpha=0.3)
    return halffreesphere
#



def animate(i):

    global pos_pb_now, pos_pb_now_shared, pos_pb_target, p_b, pos_pb_deltamove
    global pos_pw_now, pos_pw_now_shared, pos_pw_target, p_w, pos_pw_deltamove
    global pos_ball_now, pos_ball_now_shared, pos_ball_target, p_ball, pos_ball_deltamove
    global Frame
    global count_iter
    global video_page_iter
    global azimut_shared
    global elevation_shared
    global EmitPosOneWin
    global EmitPosFourWin
    global ax1
    global free_sphere
    #
    azimut, elevation = ax1.azim, ax1.elev
#    print ("azimut from main",azimut)
    azimut_shared.value = azimut
#    print ("azimut_shared value from main",azimut_shared.value)
    elevation_shared.value = elevation

    pos_ball_now[0,0] += (1. / Frame) * pos_ball_deltamove[0,0]
    pos_ball_now[0,1] += (1. / Frame) * pos_ball_deltamove[0,1]
    pos_ball_now[0,2] += (1. / Frame) * pos_ball_deltamove[0,2]
    #
#    EmitPosOneWin.put(['bp', 0, pos_ball_now[0,0], pos_ball_now[0,1], pos_ball_now[0,2]])
#    EmitPosFourWin.put(['bp', 0, pos_ball_now[0,0], pos_ball_now[0,1], pos_ball_now[0,2]])
    pos_ball_now_shared[0] = pos_ball_now[0, 0]
    pos_ball_now_shared[1] = pos_ball_now[0, 1]
    pos_ball_now_shared[2] = pos_ball_now[0, 2]

    for j in range(6):
        pos_pb_now[j, 0] += (1. / Frame) * pos_pb_deltamove[j, 0]
        pos_pb_now[j, 1] += (1. / Frame) * pos_pb_deltamove[j, 1]
        pos_pb_now[j, 2] += (1. / Frame) * pos_pb_deltamove[j, 2]

        pos_pw_now[j, 0] += (1. / Frame) * pos_pw_deltamove[j, 0]
        pos_pw_now[j, 1] += (1. / Frame) * pos_pw_deltamove[j, 1]
        pos_pw_now[j, 2] += (1. / Frame) * pos_pw_deltamove[j, 2]

        #
        # feed the queue; queue because that animation could be paused
#        EmitPosOneWin.put(['pb', j, pos_pb_now[j, 0], pos_pb_now[j, 1], pos_pb_now[j, 2]])
#        EmitPosOneWin.put(['pw', j, pos_pw_now[j, 0], pos_pw_now[j, 1], pos_pw_now[j, 2]])
#        EmitPosFourWin.put(['pb', j, pos_pb_now[j, 0], pos_pb_now[j, 1], pos_pb_now[j, 2]])
#        EmitPosFourWin.put(['pw', j, pos_pw_now[j, 0], pos_pw_now[j, 1], pos_pw_now[j, 2]])
        pos_pb_now_shared[j*3] = pos_pb_now[j,0]
        pos_pb_now_shared[j*3+1] = pos_pb_now[j,1]
        pos_pb_now_shared[j*3+2] = pos_pb_now[j,2]
        pos_pw_now_shared[j*3] = pos_pw_now[j,0]
        pos_pw_now_shared[j*3+1] = pos_pw_now[j,1]
        pos_pw_now_shared[j*3+2] = pos_pw_now[j,2]
        #

    p_b._offsets3d = pos_pb_now[:, 0], pos_pb_now[:, 1], pos_pb_now[:, 2]
    p_w._offsets3d = pos_pw_now[:, 0], pos_pw_now[:, 1], pos_pw_now[:, 2]
    p_ball._offsets3d = pos_ball_now[:,0],pos_ball_now[:,1],pos_ball_now[:,2]

    #
    video_page_iter = video_page_iter+1 # if video is on
    plt.savefig("/home/family/Bilder" + "/file%03d.png" % video_page_iter)  # if video is on
    #
    if video_page_iter==100:   # or if command store video
        os.chdir("/home/family/Bilder")
        subprocess.call([
            'ffmpeg', '-framerate', '8', '-i', 'file%03d.png', '-r', '30', '-pix_fmt', 'yuv420p',
            'video_name.mp4'
        ])
        for file_name in glob.glob("*.png"):
            os.remove(file_name)
        video_page_iter = 0
        # simulate the deletion of the free domain. Will be activated later by a GUI
        free_sphere.remove()
#        fig.canvas.draw()

    if i == (Frame - 1):
        # reset the deltamove to a clean zero for last position in case of rounding elements
        # or set to next step of dynamic move
        count_iter = count_iter+1
        m, s = divmod(count_iter, 2)
        if s == 1:
            pos_ball_deltamove[0,0] = -1.
            pos_ball_deltamove[0,1] = -1.
            pos_ball_deltamove[0,2] = -1.
            for k in range(6):
                pos_pb_deltamove[k, 0] = -1.
                pos_pb_deltamove[k, 1] = -1.
                pos_pb_deltamove[k, 2] = -1.
                pos_pw_deltamove[k, 0] = -1.
                pos_pw_deltamove[k, 1] = -1.
                pos_pw_deltamove[k, 2] = -1.
        else:
            pos_ball_deltamove[0,0] = 1.
            pos_ball_deltamove[0,1] = 1.
            pos_ball_deltamove[0,2] = 1.
            for k in range(6):
                pos_pb_deltamove[k, 0] = 1.
                pos_pb_deltamove[k, 1] = 1.
                pos_pb_deltamove[k, 2] = 1.
                pos_pw_deltamove[k, 0] = 1.
                pos_pw_deltamove[k, 1] = 1.
                pos_pw_deltamove[k, 2] = 1.

        pos_ball_now[0,0] = pos_ball_target[0,0]
        pos_ball_now[0,1] = pos_ball_target[0,1]
        pos_ball_now[0,2] = pos_ball_target[0,2]
        pos_ball_now_shared[0] = pos_ball_now[0, 0]
        pos_ball_now_shared[1] = pos_ball_now[0, 1]
        pos_ball_now_shared[2] = pos_ball_now[0, 2]

        for k in range(6):
            pos_pb_now[k, 0] = pos_pb_target[k, 0]
            pos_pb_now[k, 1] = pos_pb_target[k, 1]
            pos_pb_now[k, 2] = pos_pb_target[k, 2]
            pos_pw_now[k, 0] = pos_pw_target[k, 0]
            pos_pw_now[k, 1] = pos_pw_target[k, 1]
            pos_pw_now[k, 2] = pos_pw_target[k, 2]
            pos_pb_now_shared[k * 3] = pos_pb_now[k, 0]
            pos_pb_now_shared[k * 3 + 1] = pos_pb_now[k, 1]
            pos_pb_now_shared[k * 3 + 2] = pos_pb_now[k, 2]
            pos_pw_now_shared[k * 3] = pos_pw_now[k, 0]
            pos_pw_now_shared[k * 3 + 1] = pos_pw_now[k, 1]
            pos_pw_now_shared[k * 3 + 2] = pos_pw_now[k, 2]

        #
if __name__=="__main__":
    #
    # Set up formatting for the movie files
#    Writer = animation.writers['ffmpeg']
#    writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800)
#    writer = Writer(fps = 30, extra_args = ['-vcodec', 'libx264'])
    #
    ######## define the queues for the 2 detached plot processes
    mp.set_start_method('spawn')
    #
#    EmitPosOneWin = mp.Queue()
#    EmitPosFourWin = mp.Queue()
    #########################
    # swimmingpool size
    s_w = 10.0
#    s_w_shared = Value('d', 10.0)
    s_w_shared = mp.Value('f', 10.0)
    #
    s_d = 4.0
    s_d_shared = mp.Value('f', 4.0)
    #
    s_l = 18.0
    s_l_shared = mp.Value('f', 18.0)
    # exchange lane width
    el_w = 1.0  # normally 3
    el_w_shared = mp.Value('f', 1.0)  # just 1m in order to show the side
    # ball radius
#    b_r = 0.53 / (2 * math.pi)
#    b_r_shared = Value('d', 0.53 / (2 * math.pi))
    #
    elevation_shared = mp.Value('f', 10.)
    azimut_shared = mp.Value('f', 30.)
    #
    # define/initiate teams blue and white; array

    pos_pb_now = []
    pos_pb_now_shared = mp.Array('f',3*6)

    pos_pb_target = []

    pos_pw_now = []
    pos_pw_now_shared = mp.Array('f',3*6)

    pos_pw_target = []
    pos_pb_deltamove = []
    pos_pw_deltamove = []
    #
    pos_ball_now = []
    pos_ball_now_shared = mp.Array('f',3)

    pos_ball_target = []
    pos_ball_deltamove = []
    #
    numb_seq = 0
    video_page_iter = 0
    #
    pos_ball_now.append([5.,9.,0.2]) # ball in the middle
    pos_ball_target.append([5.,9.,0.2])
    pos_ball_deltamove.append([0., 0., 0.])
    #
    for i in range(6):
        # distribute the players at the side with the same distance
        # at game start
        pos_pb_now.append([((s_w/6)/2)+i*(s_w/6),1.0, s_d])
        pos_pb_target.append([((s_w/6)/2)+i*(s_w/6),1.0, s_d])
        pos_pw_now.append([s_w - ((s_w / 6) / 2) - i * (s_w / 6), s_l - 1.0, s_d])
        pos_pw_target.append([s_w - ((s_w / 6) / 2) - i * (s_w / 6), s_l - 1.0, s_d])
        pos_pb_deltamove.append([0., 0., 0.])
        pos_pw_deltamove.append([0., 0., 0.])
    #
    # Define numpy array which is faster to work with
    pos_pb_now = np.array(pos_pb_now, dtype='f')
    pos_pb_target = np.array(pos_pb_target, dtype='f')
    pos_pw_now = np.array(pos_pw_now, dtype='f')
    pos_pw_target = np.array(pos_pw_target, dtype='f')
    pos_pb_deltamove = np.array(pos_pb_deltamove, dtype='f')
    pos_pw_deltamove = np.array(pos_pw_deltamove, dtype='f')
    #
    pos_ball_now = np.array(pos_ball_now, dtype='f')
    pos_ball_target = np.array(pos_ball_target, dtype='f')
    pos_ball_deltamove = np.array(pos_ball_deltamove, dtype='f')
    #
    #
    fig = plt.figure()
    ax1 = fig.add_subplot(111,projection='3d')
    # field
    xG = [0,s_w,s_w,0,0, 0,s_w,s_w,s_w,s_w,s_w, 0, 0,0, 0,s_w]
    yG = [0, 0, 0,0,0,s_l,s_l, 0, 0,s_l,s_l,s_l,s_l,0,s_l,s_l]
    zG = [0, 0, s_d,s_d,0, 0, 0, 0, s_d, s_d, 0, 0, s_d,s_d, s_d, s_d]
    ax1.plot_wireframe (xG,yG,zG,colors= (0,0,1,1))  # blue line game area
    # exchange area
    xW = [s_w,s_w+el_w,s_w+el_w,s_w,s_w,s_w,s_w+el_w,s_w+el_w,s_w+el_w,s_w+el_w,s_w+el_w,s_w,s_w,s_w,s_w,s_w+el_w]
    yW = [0,  0, 0, 0, 0,s_l,s_l, 0, 0,s_l,s_l,s_l,s_l, 0,s_l,s_l]
    zW = [0,  0, s_d, s_d, 0, 0, 0, 0, s_d, s_d, 0, 0, s_d, s_d, s_d, s_d]
    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, s_w]
    yG1 = [s_d, s_d]
    zG1 = [0, 0]
    ax1.plot_wireframe(xG1, yG1, zG1, colors=(0, 0, 1, 1),linestyle=':')  # blue line
    xG2 = [0, s_w]
    yG2 = [s_l-s_d, s_l-s_d]
    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, s_w+el_w)
    ax1.set_ylim3d(0, s_l)
    ax1.set_zlim3d(0, s_d)
    #
    # use a factor for having y = x in factor
#    ax1.set_aspect(aspect=0.222)
#    ax1.set_aspect("equal")
    ax1.set_aspect(aspect=0.15)  # the best

    #
    # sphere red ball for playing
#    draw_ball(ax1, 5, 9, b_r, label="",color='r',ball_radius=b_r) # user scatter point instead
    #
    # define the basket1
    draw_basket(ax1, s_w / 2, 0.24, 0., 0.45)
    #
    # define the basket2
    draw_basket(ax1, s_w / 2, s_l - 0.24, 0., 0.45)
    #
    free_sphere = draw_halfsphere(ax1, 5., 9., 4., 2.)
    #
    p_b = ax1.scatter(pos_pb_now[:, 0], pos_pb_now[:, 1], pos_pb_now[:, 2],
                          s=400, alpha = 0.5, c=(0, 0, 1, 1))
    p_w = ax1.scatter(pos_pw_now[:, 0], pos_pw_now[:, 1],
                      pos_pw_now[:, 2], s=400, alpha = 0.5, c="darkgrey")

    p_ball = ax1.scatter(pos_ball_now[:,0], pos_ball_now[:,1],
                      pos_ball_now[:,2], s=100, alpha = 0.5, c="red")
    #
    #Add labels  ..  number and not the numbers defined in the player function (feature tbd)
    for j, xyz_ in enumerate(pos_pb_now):
        annotate3D(ax1, s=str(j+1), xyz=xyz_, fontsize=10, xytext=(-3,3),
                   textcoords='offset points', ha='right',va='bottom')
    for j, xyz_ in enumerate(pos_pw_now):
        annotate3D(ax1, s=str(j+1), xyz=xyz_, fontsize=10, xytext=(-3,3),
                   textcoords='offset points', ha='right', va='bottom')

    Frame = 10   # 2 for debugging else put it higher later for smooth movements

    for j in range(6):
        pos_pb_deltamove[j, 0] = 1.
        pos_pb_deltamove[j, 1] = 1.
        pos_pb_deltamove[j, 2] = 1.

        pos_pw_deltamove[j, 0] = 1.
        pos_pw_deltamove[j, 1] = 1.
        pos_pw_deltamove[j, 2] = 1.

    pos_ball_deltamove[0,0] = 1.
    pos_ball_deltamove[0,1] = 1.
    pos_ball_deltamove[0,2] = 1.

    count_iter = 0

    ani1 = animation.FuncAnimation(fig, animate, frames=Frame, interval=600, blit=False, repeat=True, repeat_delay=500)

    plt.pause(0.001)

#    ani1.save('uwr_game.mp4', writer=writer)

    plt.show()
floppy_molly
  • 175
  • 1
  • 10
  • What do you mean by "pausing the video"? – ImportanceOfBeingErnest Feb 21 '18 at 21:55
  • stop it (not cancel it); and easy restart. Like the "def anim_video". But only the video. Not both animation and video together. – floppy_molly Feb 21 '18 at 22:03
  • The video is saved to `'rug_game.mp4'` before the GUI even appears on screen. It's hence not exactly clear what you are trying to get at. – ImportanceOfBeingErnest Feb 21 '18 at 22:11
  • I will have a look again at it. plt.show() and gtk.main() were part of the main script. – floppy_molly Feb 22 '18 at 16:58
  • You are right. I was too quick or mixed up several things. I was thinking the video is stored. But no. Only a picture is stored. So, first I will have to make the storage of the whole video working before I will have to think about pausing it. Sorry. I will come back here later with a working code (I am new to python and having a lot of issues in parallel like multiprocessing, GUI Pygtk, storing data, etc. in the same project) – floppy_molly Feb 22 '18 at 17:27

0 Answers0