a)在下面的脚本中,只有1个FuncAnimation循环存储为视频。如何使视频存储永无止境的Funcanimation? (当我摧毁主窗口时它会停止)
b)如何从例如用PyGTK制作的GUI中的信号控制这样的视频(开始/停止)?控制将发生在从不FuncAnimation的平行(没有停止的funcanimation) 欢迎提出任何建议。
更新1: 通过在“FuncAnimation”调用的“animate”中添加以下代码,我创建了稍后将在一个视频中放在一起的图片。通过从GUI控制图片计数,我可以限制视频的大小,停止它,暂停它..主题关闭。通过阅读以下内容,我们解决了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()