Can't get my program to animate multiple patches in python matplotlib - python

I am attempting to animate two different particles in matplotlib (python). I just figured out a way to animate one particle in matplotlib, but I am havign difficulties trying to get the program to work with multiple particles. Does anyone know what is wrong and how to fix it?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
#enemy.center = (5, 5)
#agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
patches = []
enemy.center = (5, 5)
agent.center = (5, 5)
enemy_patches = animateCos(i,agent)
agent_patches = animateLine(i,enemy)
patches[enemy_patches, agent_patches]
#patches.append(ax.add_patch(enemy_patches))
#patches.append(ax.add_patch(agent_patches))
return enemy_patches
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True)
plt.show()
Working code for animating one particle
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(enemy)
ax.add_patch(agent)
return enemy,
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animateCos,
init_func=init,
frames=360,
fargs=(enemy,),
interval=20,
blit=True)
plt.show()

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
animateCos(i,enemy)
animateLine(i,agent)
return []
def animateLine(i, patch):
x, y = patch.center
x += 0.25
y += 0.25
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x += 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True,
repeat=True)
plt.show()

Related

chart_pie index to generate

I need help to generate this graph, especially with domains limits
and the arrow indicating the domain
all I can do is generate the domains name but not the limits and arrow
The following code will produce something like what you require:
from matplotlib import pyplot as plt
from matplotlib.patches import Wedge
import numpy as np
labels = ["Obésité\nmassive", "Obésité", "Surpoids", "Normal", "Maigreur"]
innerlabels = [">40", "30 à 40", "25 à 30", "18,5 à 25", "< 18,5"]
colours = ["red", "darkorange", "orange", "green", "blue"]
fig, ax = plt.subplots(figsize=(6, 6), dpi=200)
theta = 0
dtheta = 180 / len(labels)
width = 0.35
def pol2cart(rho, phi):
x = rho * np.cos(phi)
y = rho * np.sin(phi)
return(x, y)
patches = []
for i in range(len(labels)):
# outer wedge
wedge = Wedge(0, r=1, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], alpha=0.6, edgecolor="whitesmoke")
ax.add_patch(wedge)
# inner wedge
wedge = Wedge(0, r=1 - width, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], edgecolor="whitesmoke")
ax.add_patch(wedge)
theta += dtheta
# add text label
tr = 1 - (width / 2)
ta = theta - dtheta / 2
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, labels[i], rotation=textangle, va="center", ha="center", color="white", fontweight="bold")
# inner labels
tr = (1 - width) - (width / 2)
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, innerlabels[i], rotation=textangle, va="center", ha="center", color="white")
ax.set_xlim([-1, 1])
ax.set_ylim([0, 1])
ax.set_axis_off()
ax.set_aspect("equal")
def bmiposition(bmi):
"""
Get angular position of BMI arrow.
"""
from scipy.interpolate import interp1d
bmiranges = [(0, 18.5), (18.5, 25), (25, 30), (30, 40), (40, 80)]
angrange = [(180 - dtheta * i, 180 - dtheta * (i + 1)) for i in range(len(bmiranges))]
interpfuncs = []
for i in range(len(bmiranges)):
interpfuncs.append(interp1d(bmiranges[i], angrange[i], kind="linear"))
bmiang = np.piecewise(
bmi,
[bmiranges[i][0] < bmi <= bmiranges[i][1] for i in range(len(bmiranges))],
interpfuncs,
)
return bmiang
bmi = 22.5 # set BMI
# add arrow
pos = bmiposition(bmi) # get BMI angle
x, y = pol2cart(0.25, np.deg2rad(pos))
ax.arrow(0, 0, x, y, head_length=0.125, width=0.025, fc="k")
ax.plot(0, 0, 'ko', ms=10) # circle at origin
giving:

How to use python matplot animation to draw the change of grid color

I want to create a simple animation to show my data changes.
create a 3 * 3 grid.
I have an array which is 20 * 9. The data is read into the animation line by line.
Color = [[0,0,0,0,0,0,0,0,0],
[100,0,0,0,100,0,0,0,0,0],
[80,0,80,0,80,100,0,0,0]
......]
I hope the list for the grid is read line by line and each line works for 100ms. If the number is more than 0, the color of the grid change into red. For example, in the first 100ms, all color is black, then, in the second 100ms, grid number 0 and grid number 4 change to red and last for 100ms. In the third 100ms, grid number 0,2,4,5 change to red and last for 100ms.
My current version of the code looks like this. I don't know how to draw like what I describe above.
%matplotlib notebook ## show in jupyter
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')
def init():
patch.center = (5, 5)
ax.add_patch(patch)
return patch,
def animate(i):
x, y = patch.center
x = 5 + 3 * np.sin(np.radians(i))
y = 5 + 3 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=360,
interval=20,
blit=True)
plt.show()
I would appreciate it a lot if anyone could help me!!!
Cool question! I have an answer that works but it changes the structure of your Colors list. Here's the answer with an explanation below.
%matplotlib notebook
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')
colors = [
[["black", None, None], ["black", None, "black"], [None, None, "red"]],
[["black", None, None], ["black", None, "red"], ["black", None, "red"]],
[["red", None, None], [None, None, None], [None, None, "red"]],
]
def get_coords(colors):
y = 0
x = 0
coords = []
for row in colors:
x = 0
for entry in row:
if entry:
coords.append([entry, x, y])
x += 3.33
y += 3.33
return coords
def get_grids(coord):
return [plt.Rectangle((x[1], x[2]), 3.33, 3.33, fc=x[0]) for x in coord]
coords = [get_coords(color) for color in colors]
grids = [get_grids(coord) for coord in coords]
def init():
patch.center = (5, 5)
ax.add_patch(patch)
return patch,
def animate(i):
patches = []
if (i % 100 == 0):
ax.patches = []
next_grid = grids.pop(0)
for rectangle in next_grid:
patches.append(ax.add_patch(rectangle))
x, y = patch.center
x = 5 + 3 * np.sin(np.radians(i))
y = 5 + 3 * np.cos(np.radians(i))
patch.center = (x, y)
patches.append(ax.add_patch(patch))
return patches
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=360,
interval=20,
blit=True)
plt.show()
The key idea is adding and removing plt.Rectangles to give the appearance of a grid. Because your graph is 10x10, these rectangles are squares of side length 10/3 =~ 3.33.
I think it's easier to use 20 * 3 * 3 instead of a 20 * 9 list for the colors. I use the following:
colors = [
[["black", None, None], ["black", None, "black"], [None, None, "red"]],
[["black", None, None], ["black", None, "red"], ["black", None, "red"]],
[["red", None, None], [None, None, None], [None, None, "red"]],
]
Each entry in this list, as yours, is a grid. Within these grids, however, are rows, each with a desired color entry. colors[0][0] == ["black", None, None] means at the first frame of the animation, the bottom left corner of the grid will be black and the rest of the bottom transparent. colors[0][1] == ["black", None, "black"] means the middle of the grid will have the left and right thirds black with the middle transparent.
The get_coords and get_grids functions are pretty hairy and clearly hard-coded to support a 3x3 grid with dimensions 10x10 - it'd be cool to parameterize that out down the line.
Only other important idea is that to change the animation every 100ms, we just check if i in the animate function is divisible by 100. If it is, we clear the existing patches (so we're not just adding rectangles ad nausem) and plot our new ones. When the grid list runs out, the grid will be transparent for the rest of the animation.
Hope this helps - happy plotting!
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
Color = [[0,0,0,0,0,0,0,0,0],
[100,0,0,0,100,0,0,0,0,0],
[80,0,80,0,80,100,0,0,0]]
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
fig.set_tight_layout(True)
ax = plt.axes(xlim=(0, 6), ylim=(0, 6))
patch = []
patch.append(plt.Rectangle(xy = (0,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (0,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (0,4),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,4),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,4),width = 2,height = 2,fill = True,color = 'k'))
def init():
for i in range(9):
patch[i].set_color('k')
ax.add_patch(patch[i])
return patch
def animate(i):
value = (np.array(Color[i]) == 0)
for j in range(9):
patch[j].set_color('k' if value[j] else 'r')
return patch
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=3,
interval=1000,
blit=True)
plt.show()

bokeh (python) export_svgs doesn't render image alpha

I'm having trouble getting bokeh.io.export_svgs() to output an image with alpha correctly.
Toy example:
import numpy as np
import bokeh.plotting as bk_plt
import bokeh.io as bk_io
bk_plt.output_notebook()
N = 500
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)
p1 = bk_plt.figure(x_range=(0, 10), y_range=(0, 10))
p1.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", alpha = 0.5)
bk_plt.show(p1)
p2 = bk_plt.figure(x_range=(0, 10), y_range=(0, 10))
p2.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", alpha = 0.5)
p2.output_backend = 'svg'
bk_io.export_svgs(p2, filename = 'asdf.svg')
bk_plt.show(p2)
Bokeh correctly outputs this to notebook:
export_svgs() incorrectly outputs this:
Is there an easy way to fix this?
Found a workable solution - create an rgba image and plot it instead:
import numpy as np
import bokeh.plotting as bk_plt
import bokeh.palettes as bk_pal
import bokeh.io as bk_io
bk_plt.output_notebook()
N = 500
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)
def Make_RGBA(Val, Palette, alpha):
X, Y = Val.shape
Pal = [tuple(int(P[i:i+2], 16) for i in (1, 3 ,5)) for P in Palette]
a = (len(Pal)) / (Val.max() - Val.min())
b = Val.min()
Temp_Val = (a * (Val - b)).astype(int)
Temp_Val = np.minimum(Temp_Val, len(Pal) - 1)
img = np.empty((X, Y), dtype=np.uint32)
view = img.view(dtype=np.uint8).reshape((X, Y, 4))
for i in range(X):
for j in range(Y):
view[i, j, 0] = Pal[Temp_Val[i][j]][0]
view[i, j, 1] = Pal[Temp_Val[i][j]][1]
view[i, j, 2] = Pal[Temp_Val[i][j]][2]
view[i, j, 3] = 255 * alpha
return img
img = Make_RGBA(d, bk_pal.Spectral11, 0.5)
p1 = bk_plt.figure(x_range=(0, 10), y_range=(0, 10))
p1.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", alpha = 0.5)
bk_plt.show(p1)
p2 = bk_plt.figure(x_range=(0, 10), y_range=(0, 10))
p2.image_rgba(image=[img], x=[0], y=[0], dw=[10], dh=[10])
p2.output_backend = 'svg'
bk_io.export_svgs(p2, filename = 'asdf.svg')
bk_plt.show(p2)

Python 3.5.4 matplotlib can not draw the animated figure

I want to draw an animated chart using python3.5.4's matplotlib package, the examples of matplotlib official website works well on my local Python environment.
But those codes I wrote can not show me any chart, I can not figure out what's problem in those codes, so I come here to look for some help. Here are my codes.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class Plot(object):
def __init__(self, update_func, frames):
self.x_data, self.y_data = [], []
self.update_func = update_func
self.frames = frames
self.t = 0
def draw(self):
fig = plt.figure()
self.ax = plt.axes()
self.line, = self.ax.plot([1, 2, 3, 4], [1, 2, 3, 4], lw=2)
# Without invoke the FuncAnimation can display the chart.
self.ani_ref = FuncAnimation(fig, self._update, frames=self.frames, blit=True,
interval=20, init_func=self._animation_init)
plt.show()
def _animation_init(self):
self.line.set_data(self.x_data, self.y_data)
return self.line
def _update(self, i):
# modified the data from outside update function
self.x_data, self.y_data = self.update_func(self.x_data, self.y_data)
x_min, x_max = self.ax.get_xlim()
y_min, y_max = self.ax.get_ylim()
if np.max(self.x_data) >= x_max:
x_max = np.max(self.x_data) + 10
if np.min(self.x_data) <= x_min:
x_min = np.min(self.x_data) - 10
if np.max(self.y_data) >= y_max:
y_max = np.max(self.y_data) + 10
if np.min(self.y_data) <= y_min:
y_min = np.min(self.y_data) - 10
self.ax.set_xlim(x_min, x_max)
self.ax.set_ylim(y_min, y_max)
self.ax.figure.canvas.draw()
self.line.set_data(self.x_data, self.y_data)
return self.line
if __name__ == "__main__":
def update(x_data, y_data):
x, y = x_data[-1], np.sin(2 * np.pi * (x_data[-1] + 0.1))
x_data.append(x)
y_data.append(y)
return x_data, y_data
p = Plot(update_func=update, frames=100)
p.draw()

Shading over plot with funcanimation

I'm trying to shade over a map to show "explored regions" of the dot as it moves around using FuncAnimation. This is the code I have so far:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.animation as animation
import numpy as np
import random
import scipy.stats as stats
map_x = 100
map_y = 100
fig = plt.figure(0)
plt.figure(0)
ax1 = plt.subplot2grid((2,3), (0,0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((2,3), (0,2), colspan=1)
ax1.set_xlim([0, map_x])
ax1.set_ylim([0, map_y])
ax2.set_xlim([0, map_x])
ax2.set_ylim([0, map_y])
agent = plt.Circle((50, 1), 2, fc='r')
agent2 = plt.Circle((50, 1), 2, fc='r')
agents = [agent, agent2]
ax1.add_patch(agent)
ax2.add_patch(agent2)
def animate(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
agent2.center = (x, y)
return agent,
def fillMap(x, y):
circle=plt.Circle((x,y), 4, fc='b')
ax2.add_patch(circle)
def animate2(i):
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
fillMap(x, y)
return agent2,
anim = animation.FuncAnimation(fig, animate, frames=200, interval=20, blit=True)
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=True)
plt.show()
However, it only goes into fillMap once, and only draws the blue filled in circle once, instead of everywhere where the red dot goes in the smaller subplot.
If you want the circle you added to persist on the screen you probably shouldn't use blitting. Not using blitting makes the animation slower, but it may be enough to draw a new blue circle every 20th step or so.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.animation as animation
import numpy as np
import scipy.stats as stats
map_x = 100
map_y = 100
fig = plt.figure(0)
plt.figure(0)
ax1 = plt.subplot2grid((2,3), (0,0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((2,3), (0,2), colspan=1)
ax1.set_xlim([0, map_x])
ax1.set_ylim([0, map_y])
ax2.set_xlim([0, map_x])
ax2.set_ylim([0, map_y])
agent = plt.Circle((50, 1), 2, fc='r')
agent2 = plt.Circle((50, 1), 2, fc='r')
agents = [agent, agent2]
ax1.add_patch(agent)
ax2.add_patch(agent2)
def fillMap(x, y):
circle=plt.Circle((x,y), 4, fc='b')
ax2.add_patch(circle)
def animate2(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
if i%20==0:
circle = fillMap(x, y)
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=False)
plt.show()
In case you want to use blitting, consider using a line to mark the region where the circle has been.
line, =ax2.plot([],[], lw=3, color="b")
xl = []; yl=[]
def fillMap(x, y):
xl.append(x); yl.append(y)
line.set_data(xl,yl)
return line
def animate2(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
if i%20==0:
fillMap(x, y)
return agent, agent2, line
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=True)

Categories

Resources