Dynamic updating a Matplotlib 3D plot when working with ROS callback - python

I am trying to update a 3D plot using matplotlib. I am collecting data using ROS. I want to update the plot as I get data. I have looked around and found this,
Dynamically updating plot in matplotlib
but I cannot get it to work. I am very new to python and do not full understand how it works yet. I apologize if my code is disgusting.
I keep get this error.
[ERROR] [WallTime: 1435801577.604410] bad callback: <function usbl_move at 0x7f1e45c4c5f0>
Traceback (most recent call last):
File "/opt/ros/indigo/lib/python2.7/dist-packages/rospy/topics.py", line 709, in _invoke_callback
cb(msg, cb_args)
File "/home/nathaniel/simulation/src/move_videoray/src/move_filtered.py", line 63, in usbl_move
if filter(pos.pose.position.x,pos.pose.position.y,current.position.z):
File "/home/nathaniel/simulation/src/move_videoray/src/move_filtered.py", line 127, in filter
plt.draw()
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 555, in draw
get_current_fig_manager().canvas.draw()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 349, in draw
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)
File "/usr/lib/pymodules/python2.7/matplotlib/backends/tkagg.py", line 13, in blit
tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array))
RuntimeError: main thread is not in main loop
This is the code I am trying to run
#!/usr/bin/env python
'''
Ths program moves the videoray model in rviz using
data from the /usble_pose node
based on "Using urdf with robot_state_publisher" tutorial
'''
import rospy
import roslib
import math
import tf
#import outlier_filter
from geometry_msgs.msg import Twist, Vector3, Pose, PoseStamped, TransformStamped
from matplotlib import matplotlib_fname
from mpl_toolkits.mplot3d import Axes3D
import sys
from matplotlib.pyplot import plot
from numpy import mean, std
import matplotlib as mpl
import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
#plt.ion()
import matplotlib
mpl.rc("savefig", dpi=150)
import matplotlib.animation as animation
import time
#filter stuff
#window size
n = 10
#make some starting values
#random distance
md =[random.random() for _ in range(0, n)]
#random points
x_list = [random.random() for _ in range(0, n)]
y_list =[random.random() for _ in range(0, n)]
#set up graph
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.scatter(filt_x,filt_y,filt_depth,color='b')
#ax.scatter(outlier_x,outlier_y,outlier_depth,color='r')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('XY Outlier rejection \n with Mahalanobis distance and rolling mean3')
#set the robot at the center
#//move the videoray using the data from the /pose_only node
def usbl_move(pos,current):
broadcaster = tf.TransformBroadcaster()
if filter(pos.pose.position.x,pos.pose.position.y,current.position.z):
current.position.x = pos.pose.position.x
current.position.y = pos.pose.position.y
broadcaster.sendTransform( (current.position.x,current.position.y,current.position.z),
(current.orientation.x,current.orientation.y,current.orientation.z,current.orientation.w),
rospy.Time.now(), "odom", "body" )
#move the videoray using the data from the /pose_only node
def pose_move(pos,current):
#pos.position.z is in kPa, has to be convereted to depth
# P = P0 + pgz ----> pos.position.z = P0 + pg*z_real
z_real = -1*(pos.position.z -101.325)/9.81;
#update the movement
broadcaster = tf.TransformBroadcaster()
current.orientation.x = pos.orientation.x
current.orientation.y = pos.orientation.y
current.orientation.z = pos.orientation.z
current.orientation.w = pos.orientation.w
current.position.z = z_real
broadcaster.sendTransform( (current.position.x,current.position.y,current.position.z),
(current.orientation.x,current.orientation.y,current.orientation.z,current.orientation.w),
rospy.Time.now(), "odom", "body" )
#call the fitle the date
def filter(x,y,z):
# update the window
is_good = False
x_list.append(x)
y_list.append(y)
x_list.pop(0)
y_list.pop(0)
#get the covariance matrix
v = np.linalg.inv(np.cov(x_list,y_list,rowvar=0))
#get the mean vector
r_mean = mean(x_list), mean(y_list)
#subtract the mean vector from the point
x_diff = np.array([i - r_mean[0] for i in x_list])
y_diff = np.array([i - r_mean[1] for i in y_list])
#combinded and transpose the x,y diff matrix
diff_xy = np.transpose([x_diff, y_diff])
# calculate the Mahalanobis distance
dis = np.sqrt(np.dot(np.dot(np.transpose(diff_xy[n-1]),v),diff_xy[n-1]))
# update the window
md.append( dis)
md.pop(0)
#find mean and standard standard deviation of the standard deviation list
mu = np.mean(md)
sigma = np.std(md)
#threshold to find if a outlier
if dis < mu + 1.5*sigma:
#filt_x.append(x)
#filt_y.append(y)
#filt_depth.append(z)
ax.scatter(x,y,z,color='b')
is_good = True
else:
ax.scatter(x,y,z,color='r')
plt.draw()
return is_good
if __name__ == '__main__':
#set up the node
rospy.init_node('move_unfiltered', anonymous=True)
#make a broadcaster foir the tf frame
broadcaster = tf.TransformBroadcaster()
#make intilial values
current = Pose()
current.position.x = 0
current.position.y = 0
current.position.z = 0
current.orientation.x = 0
current.orientation.y = 0
current.orientation.z = 0
current.orientation.w = 0
#send the tf frame
broadcaster.sendTransform( (current.position.x,current.position.y,current.position.z),
(current.orientation.x,current.orientation.y,current.orientation.z,current.orientation.w),
rospy.Time.now(), "odom", "body" )
#listen for information
rospy.Subscriber("/usbl_pose", PoseStamped, usbl_move,current)
rospy.Subscriber("/pose_only", Pose, pose_move, current);
rospy.spin()

Since this is an old post and still seems to be active in the community, I am going to provide an example, in general, how can we do real-time plotting. Here I used matplotlib FuncAnimation function.
import matplotlib.pyplot as plt
import rospy
import tf
from nav_msgs.msg import Odometry
from tf.transformations import quaternion_matrix
import numpy as np
from matplotlib.animation import FuncAnimation
class Visualiser:
def __init__(self):
self.fig, self.ax = plt.subplots()
self.ln, = plt.plot([], [], 'ro')
self.x_data, self.y_data = [] , []
def plot_init(self):
self.ax.set_xlim(0, 10000)
self.ax.set_ylim(-7, 7)
return self.ln
def getYaw(self, pose):
quaternion = (pose.orientation.x, pose.orientation.y, pose.orientation.z,
pose.orientation.w)
euler = tf.transformations.euler_from_quaternion(quaternion)
yaw = euler[2]
return yaw
def odom_callback(self, msg):
yaw_angle = self.getYaw(msg.pose.pose)
self.y_data.append(yaw_angle)
x_index = len(self.x_data)
self.x_data.append(x_index+1)
def update_plot(self, frame):
self.ln.set_data(self.x_data, self.y_data)
return self.ln
rospy.init_node('lidar_visual_node')
vis = Visualiser()
sub = rospy.Subscriber('/dji_sdk/odometry', Odometry, vis.odom_callback)
ani = FuncAnimation(vis.fig, vis.update_plot, init_func=vis.plot_init)
plt.show(block=True)

Related

Animated points leaving trail of annotations behind

I am trying to make a virtual flight tracker with Python and API data, and I have managed so far to draw the points, update their location every 10 seconds and annotate them. Unfortunately, they are being annotated for each position they are drawn in when in fact I want them to only be shown in the spot where the point is at that time, or else there is a constant trail of labels.
The code is below:
import requests
import json
import time
import cartopy.crs as ccrs
import cartopy
import matplotlib.pyplot as plt
from cartopy.io.img_tiles import GoogleTiles
from matplotlib import animation
#SET AXES
fig, ax = plt.subplots()
ax=plt.axes(projection=ccrs.PlateCarree())
'''
ax.set_ylim(48,61.5)
ax.set_xlim(-12.5, 3.3)
'''
#ADD OSM BASEMAP
osm_tiles=GoogleTiles(style='satellite')
ax.add_image(osm_tiles,8)
ax.stock_img()
ax.set_extent([-12.5, 3.3, 48, 61.55])
ax.add_feature(cartopy.feature.BORDERS)
#mplcursors.cursor(hover=True)
#PLOT TRACK
track, = ax.plot([], [], 'wo')
# RELOAD API EVERY 15"
def update (self):
vapi = requests.get("https://data.vatsim.net/v3/vatsim-data.json")
# LOAD DATA AS JSON
data = vapi.text
parse_json = json.loads(data)
# LOAD PILOTS
pilots = parse_json['pilots']
no_pilots = len(pilots)
# GET INFO FOR EACH AIRCRAFT
x = 0
callsigns, lat, lon, alt, head, gspeed = [], [], [], [], [], []
while x < no_pilots:
xcall = pilots[x]['callsign']
xlat = pilots[x]['latitude']
xlon = pilots[x]['longitude']
xgspeed = pilots[x]['groundspeed']
xalt = pilots[x]['altitude']
xhead = pilots[x]['heading']
callsigns.append(xcall)
lat.append(xlat)
lon.append(xlon)
alt.append(xalt)
head.append(xhead)
gspeed.append(xgspeed)
x += 1
for i, txt in enumerate(callsigns):
ax.annotate(txt, (lon[i], lat[i]))
track.set_data(lon,lat)
return track, callsigns,
anim = animation.FuncAnimation(fig, update,interval=10000, blit=False)
plt.show()
It leaves a trail of annotations like this

Live waveform with python-can

I'm trying to plot can-data using the python-can and matplotlib library. I have a basic example on how to plot live data with matplotlib:
import numpy as np
import matplotlib.pyplot as plt
plt.axis([0, 10, 0, 1])
for i in range(10):
y = np.random.random()
plt.scatter(i, y)
# plt.pause(0.05)
plt.draw()
plt.show()
And I used a basic python-can example and added the matplotlib:
import sys
import argparse
import socket
from datetime import datetime
import can
from can import Bus, BusState, Logger
import numpy as np
import matplotlib.pyplot as plt
def main():
plt.axis([0, 10, 0, 1])
bus = Bus(bustype ='pcan')
i = 0
print(f"Connected to {bus.__class__.__name__}: {bus.channel_info}")
print(f"Can Logger (Started on {datetime.now()})")
plt.show()
try:
while True:
msg = bus.recv(1)
if msg is not None:
y = np.random.random()
plt.scatter(i, y)
plt.draw()
i += 1
print('Message id {id}'.format(id=msg.arbitration_id))
except KeyboardInterrupt:
pass
finally:
plt.show()
bus.shutdown()
if __name__ == "__main__":
main()
However as soon as I add the plt commands the script stops working, it just doesn't output the print statement anymore. When I Debug into it and step manually it works. Anything I'm doing wrong? Is there a better way to solve this? I'm not set on matplotlib, just the fastest way to plot something :)
I found a working solution using the blit function, its not perfect yet but its a good starting point:
from datetime import datetime
import can
from can import Bus, BusState, Logger
import numpy as np
import matplotlib.pyplot as plt
import struct
def main():
bus = Bus(bustype ='pcan')
i = 0
print(f"Connected to {bus.__class__.__name__}: {bus.channel_info}")
print(f"Can Logger (Started on {datetime.now()})")
x = np.linspace(0, 1000, num=1000)
y = np.zeros(1000)
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
line, = ax1.plot([], lw=3)
text = ax1.text(0.8, 0.5, "")
ax1.set_xlim(x.min(), x.max())
ax1.set_ylim([-10, 10])
fig.canvas.draw() # note that the first draw comes before setting data
ax2background = fig.canvas.copy_from_bbox(ax1.bbox)
plt.show(block=False)
k = 0
try:
while True:
msg = bus.recv(1)
if msg is not None:
y = np.roll(y, 1)
value = struct.unpack('f', msg.data)
y[0] = np.int8(value)
line.set_data(x, y)
fig.canvas.restore_region(ax2background)
ax1.draw_artist(line)
ax1.draw_artist(text)
fig.canvas.blit(ax1.bbox)
fig.canvas.flush_events()
# print('Message data {data}, value {value}, counter {counter}'.format(data=msg.data, value=value, counter=k))
k += 1
if k > 100:
k = 0
except KeyboardInterrupt:
pass
finally:
plt.show()
bus.shutdown()
if __name__ == "__main__":
main()
The script assumes that the can message carries one single float over the first four uint8 and just plots it.

Nothing Happens When Running Script in Spyder

I am running this code and oddly, nothing happens. There is no error nor does it freeze. It simply just runs the code without storing variables, nothing is printed out and it doesn't open the window that is supposed to show the plot. So it simply does nothing. It is very odd. This worked only a few minutes ago and I did not change anything about it previously. I did make sure that the variable explorer is displaying all the definitions in the script. I intentionally removed the plotting section at the end since it just made the code set longer and the same issue persists here without it.
Code:
#Import libraries
import numpy as np
from scipy.integrate import odeint
#from scipy.integrate import solve_ivp
from time import time
import matplotlib.pyplot as plt
from matplotlib.pyplot import grid
from mpl_toolkits.mplot3d import Axes3D
import numpy, scipy.io
from matplotlib.patches import Circle
'''
import sympy as sy
import random as rand
from scipy import interpolate
'''
'''
Initiate Timer
'''
TimeStart = time()
'''
#User defined inputs
'''
TStep = (17.8E-13)
TFinal = (17.8E-10)
R0 = 0.02
V0X = 1E7
ParticleCount = 1 #No. of particles to generate energies for energy generation
BInput = 0.64 #Magnitude of B field near pole of magnet in experiment
ScaleV0Z = 1
'''
#Defining constants based on user input and nature (Cleared of all errors!)
'''
#Defining Space and Particle Density based on Pressure PV = NkT
k = 1.38E-23 #Boltzman Constant
#Natural Constants
Q_e = -1.602E-19 #Charge of electron
M_e = 9.11E-31 #Mass of electron
JToEv = 6.24E+18 #Joules to eV conversion
EpNaut = 8.854187E-12
u0 = 1.256E-6
k = 1/(4*np.pi*EpNaut)
QeMe = Q_e/M_e
'''
Create zeros matrices to populate later (Cannot create TimeIndex array!)
'''
TimeSpan = np.linspace(0,TFinal,num=round((TFinal/TStep)))
TimeIndex = np.linspace(0,TimeSpan.size,num=TimeSpan.size)
ParticleTrajectoryMat = np.zeros([91,TimeSpan.size,6])
BFieldTracking = np.zeros([TimeSpan.size,3])
InputAngle = np.array([np.linspace(0,90,91)])
OutputAngle = np.zeros([InputAngle.size,1])
OutputRadial = np.zeros([InputAngle.size,1])
'''
Define B-Field
'''
def BField(x,y,z):
InputCoord = np.array([x,y,z])
VolMag = 3.218E-6 #Volume of magnet in experiment in m^3
BR = np.sqrt(InputCoord[0]**2 + InputCoord[1]**2 + InputCoord[2]**2)
MagMoment = np.array([0,0,(BInput*VolMag)/u0])
BDipole = (u0/(4*np.pi))*(((3*InputCoord*np.dot(MagMoment,InputCoord))/BR**5)-(MagMoment/BR**3))
#BVec = np.array([BDipole[0],BDipole[1],BDipole[2]])
#print(BDipole[0],BDipole[1],BDipole[2])
return (BDipole[0],BDipole[1],BDipole[2])
'''
Lorentz Force Differential Equations Definition
'''
def LorentzForce(PosVel,t,Constants):
X,Y,Z,VX,VY,VZ = PosVel
Bx,By,Bz,QeMe = Constants
BFInput = np.array([Bx,By,Bz])
VelInput = np.array([VX,VY,VZ])
Accel = QeMe * (np.cross(VelInput, BFInput))
LFEqs = np.concatenate((VelInput, Accel), axis = 0)
return LFEqs
'''
Cartesean to Spherical coordinates converter function. Returns: [Radius (m), Theta (rad), Phi (rad)]
'''
def Cart2Sphere(xIn,yIn,zIn):
P = np.sqrt(xIn**2 + yIn**2 + zIn**2)
if xIn == 0:
Theta = np.pi/2
else:
Theta = np.arctan(yIn/xIn)
Phi = np.arccos(zIn/np.sqrt(xIn**2 + yIn**2 + zIn**2))
SphereVector = np.array([P,Theta,Phi])
return SphereVector
'''
Main Loop
'''
for angletrack in range(0,InputAngle.size):
MirrorAngle = InputAngle[0,angletrack]
MirrorAngleRad = MirrorAngle*(np.pi/180)
V0Z = np.abs(V0X/np.sin(MirrorAngleRad))*np.sqrt(1-(np.sin(MirrorAngleRad))**2)
V0Z = V0Z*ScaleV0Z
#Define initial conditions
V0 = np.array([[V0X,0,V0Z]])
S0 = np.array([[0,R0,0]])
ParticleTrajectoryMat[0,:] = np.concatenate((S0,V0),axis=None)
for timeplace in range(0,TimeIndex.size-1):
ICs = np.concatenate((S0,V0),axis=None)
Bx,By,Bz = BField(S0[0,0],S0[0,1],S0[0,2])
BFieldTracking[timeplace,:] = np.array([Bx,By,Bz])
AllConstantInputs = [Bx,By,Bz,QeMe]
t = np.array([TimeSpan[timeplace],TimeSpan[timeplace+1]])
ODESolution = odeint(LorentzForce,ICs,t,args=(AllConstantInputs,))
ParticleTrajectoryMat[angletrack,timeplace+1,:] = ODESolution[1,:]
S0[0,0:3] = ODESolution[1,0:3]
V0[0,0:3] = ODESolution[1,3:6]
MatSize = np.array([ParticleTrajectoryMat.shape])
RowNum = MatSize[0,1]
SphereMat = np.zeros([RowNum,3])
SphereMatDeg = np.zeros([RowNum,3])
for cart2sphereplace in range(0,RowNum):
SphereMat[cart2sphereplace,:] = Cart2Sphere(ParticleTrajectoryMat[angletrack,cart2sphereplace,0],ParticleTrajectoryMat[angletrack,cart2sphereplace,1],ParticleTrajectoryMat[angletrack,cart2sphereplace,2])
for rad2deg in range(0,RowNum):
SphereMatDeg[rad2deg,:] = np.array([SphereMat[rad2deg,0],(180/np.pi)*SphereMat[rad2deg,1],(180/np.pi)*SphereMat[rad2deg,2]])
PhiDegVec = np.array([SphereMatDeg[:,2]])
RVec = np.array([SphereMatDeg[:,0]])
MinPhi = np.amin(PhiDegVec)
MinPhiLocationTuple = np.where(PhiDegVec == np.amin(PhiDegVec))
MinPhiLocation = int(MinPhiLocationTuple[1])
RAtMinPhi = RVec[0,MinPhiLocation]
OutputAngle[angletrack,0] = MinPhi
OutputRadial[angletrack,0] = RAtMinPhi
print('Mirror Angle Input (In deg): ',InputAngle[0,angletrack])
print('Mirror Angle Output (In deg): ',MinPhi)
print('R Value at minimum Phi (m): ',RAtMinPhi)
InputAngleTrans = np.matrix.transpose(InputAngle)
CompareMat = np.concatenate((InputAngleTrans,OutputAngle),axis=1)

ValueError: When providing two arguments, the array must be of shape (N, 4)

I've been trying to use pv-extractor package to extract the velocity along a certain path. then convert the position in the pixel coordinate to world coordinate and frequency to velocity. here is the code I've written:
###############################
## import packages
###############################
import matplotlib
matplotlib.use('Qt4Agg')
import matplotlib.pyplot as plt
from astropy.io import fits
from astropy import wcs
from astropy import coordinates
from astropy import units as u
import os
import aplpy
import numpy as np
from pvextractor import extract_pv_slice
from pvextractor.geometry import Path
from astropy import constants as const
import array as arr
###############################
fitsfile = fits.open('Image.fits', cache=True)
hdu = fitsfile[0]
data = hdu.data[0,:,:,:]
header = hdu.header
w = wcs.WCS(hdu.header)
###############################
## pv extract
###############################
from pvextractor import Path
list = [(1120.40,780.97), (881.37,741.97)]
path1 = Path(list, width=20 )
pv1 = extract_pv_slice(data, path1)
fig = plt.figure( )
F1 = aplpy.FITSFigure(pv1, figure=fig)
F1.show_colorscale(cmap='YlGnBu')
plt.show()
##################################
## define functions
##################################
restf = 8.6754290e10
f0 = header['CRVAL3']
f0 = np.float(f0)
df = header['CDELT3']
df = np.float(df)
ref = header['CRPIX3']
ref = np.float(ref)
chan_max = header['NAXIS3']
chan_max = np.float(chan_max)
channels = np.arange(0, chan_max) # generate array with number of channels
##################################
## velocity
##################################
f0=np.float(f0)
df=np.float(df)
freq = []
freq = f0 + ( ( channels - ref ) * df )
v = []
for i in xrange(0 , len(freq)):
v.append(const.c.value * (1 - (freq[i] / restf)))
##################################
## distance
##################################
pixcrd = np.array(list, np.float)
world = w.wcs_pix2world(pixcrd,1)
ListDist =[]
for i in renge (0, len(list)):
Pixel_x_1 =world[i][0]
Pixel_y_1 =world[i][1]
print Pixel_x_1
print Pixel_y_1
try:
Pixel_x_2 =world[i+1][0]
Pixel_y_2 =world[i+1][1]
except IndexError:
break
dist_dc = abs(Pixel_y_2 - Pixel_y_1)
dist_ra = abs(Pixel_x_2 - Pixel_x_1) * np.cos(())
ListDist.append(dist_connect)
print ListDist
dist_total = sum(ListDist) #it should be in arcsec
print dist_total
###############################
It perfectly extracts the path and shows the map, also I could extract the velocity as well but in the last step, I get the following error which I don't know how to solve it :
>>Traceback (most recent call last):
>> File "distance.py", line 43, in <module>
>> world = w.wcs_pix2world(pixcrd,1)
>> File "/usr/lib64/python2.7/site-packages/astropy/wcs/wcs.py", line 1355, in wcs_pix2world
>> 'output', *args, **kwargs)
>> File "/usr/lib64/python2.7/site-packages/astropy/wcs/wcs.py", line 1257, in _array_converter
>> return _return_single_array(xy, origin)
>> File "/usr/lib64/python2.7/site-packages/astropy/wcs/wcs.py", line 1238, in _return_single_array
>> "of shape (N, {0})".format(self.naxis))
>>ValueError: When providing two arguments, the array must be of shape (N, 4)

making animation with matplotlib.animation

I am trying to make animated gif using matplotlib. I found simple example here : https://tomroelandts.com/articles/how-to-create-animated-gifs-with-python
And now i am trying to adapt it to my problem. Below is the code i worked out :
from __future__ import division
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import proj3d
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anim
class AnimatedGif:
def __init__(self,radius = 10):
############################################################
self.fig = plt.figure(frameon=False,figsize=(12,10))
self.fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ax = Axes3D(self.fig)
ax.set_xlim((-.7*radius,.7*radius))
ax.set_ylim((-.7*radius,.7*radius))
ax.set_zlim((0*radius,1.4*radius))
ax.axis('off')
ax.xaxis.pane.set_edgecolor('black')
ax.yaxis.pane.set_edgecolor('black')
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
self.images = []
####################################################################
def add(self,step, area='',azim = 0, elev = 7,color = 'k',numOfLayer = 10,Length = 1.,alpha = 0.8,ids = False):
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import proj3d
################################################
ax = self.fig.gca()
verts = [zip([step*0.5+0.,5,1.,2,1,2],[0.,3,2.,2,1,2],[0.,9,3.,2,1,2])]
pc = Poly3DCollection(verts,alpha = alpha,linewidths=1, facecolor = color)
pc.set_edgecolor('k')
ax.add_collection3d(pc)
ax.view_init(azim = azim,elev=elev)
plt_im = ax
self.images.append([plt_im])
####################################################################
def save(self, filename):
animation = anim.ArtistAnimation(self.fig, self.images)
print animation
animation.save(filename, writer='imagemagick', fps=1)
##################################################################
endStep = 100
stepsize = 5
##################################################################
animated_gif = AnimatedGif()
step = 0
area = 0
animated_gif.add(step,area=str(area))
images = []
for step in range(stepsize+1, endStep,stepsize):
area = 10
animated_gif.add(step, area=str(area))
animated_gif.save('cell-animated1.gif')
I need to use Poly3DCollection to make bunch of polygons on 3d and they move with timestep. Here I just made a simple case with polygon moving in x-axis with step. But there is no output. The output is just blank white.
My confusion mainly came from lack of good examples on use of ArtistAnimation. On the documentation for it, artists argument is mentioned as "Each list entry a collection of artists that represent what needs to be enabled on each frame. These will be disabled for other frames.". However, I did not get what is exactly expected. I made the Poly3DCollection but again just passing it by adding it to the self.images was not enough as it needed to be added to the axes too (ax.add_collection(pc)) in the end. I figured directly images needed to be added so tried adding the pc to the collection and append the ax to the self.images, which was completely wrong in the end.
Also most of the error I got was :
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-1-bd3b8eac5524> in <module>()
56 animated_gif.add(step, area=str(area))
57
---> 58 animated_gif.save('cell-animated1.gif')
<ipython-input-1-bd3b8eac5524> in save(self, filename)
42 animation = anim.ArtistAnimation(self.fig, self.images)
43 print animation
---> 44 animation.save(filename, writer='imagemagick', fps=4)
45 ##################################################################
46 endStep = 100
/Users/name/anaconda2/lib/python2.7/site-packages/matplotlib/animation.pyc in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
1055 for anim in all_anim:
1056 # Clear the initial frame
-> 1057 anim._init_draw()
1058 for data in zip(*[a.new_saved_frame_seq()
1059 for a in all_anim]):
/Users/name/anaconda2/lib/python2.7/site-packages/matplotlib/animation.pyc in _init_draw(self)
1374 # Flush the needed figures
1375 for fig in figs:
-> 1376 fig.canvas.draw_idle()
1377
1378 def _pre_draw(self, framedata, blit):
AttributeError: 'NoneType' object has no attribute 'canvas'
I do not get the error at all. I could not find good description for canvas. I was passing fig to the save, so it should not be a None.

Categories