Embed _update_plot function in PyQt matplotlib - python

here is my update plot program which I want to put into a pyqt5 window.
I can't find any examples which use the _update_plot function they all use update_figure or a draw function with a timer whereas mine uses an i variable that updates at specified rate.
Any help/advice is appreciated
program:
import math
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons
from matplotlib import style
style.use('seaborn-poster')
def _update_plot(i, fig, scat, l,l2):
M = ((math.sin(math.radians(i))*7.5)-(math.sin(math.radians(i/2))*9))/((math.cos(math.radians(i))*7.5)-(math.cos(math.radians(i/2))*9))
g = M*(15-(math.cos(math.radians(i/2))*9))+(math.sin(math.radians(i/2))*9)
scat.set_offsets(([math.cos(math.radians(i))*7.5, math.sin(math.radians(i))*7.5], [math.cos(math.radians(i/2))*9, math.sin(math.radians(i/2))*9], [0, 0]))
if (i>=540) or (i<=180):
l.set_data(([math.cos(math.radians(i))*7.5,math.cos(math.radians(i/2))*9],[math.sin(math.radians(i))*7.5,math.sin(math.radians(i/2))*9]))
l2.set_data(([math.cos(math.radians(i/2))*9,15],[math.sin(math.radians(i/2))*9,g]))
else:
l.set_data(([0,0],[0,0]))
l2.set_data(([0,0],[0,0]))
return [scat,l,l2]
fig = plt.figure()
x = [0]
y = [0]
ax = fig.add_subplot(111)
ax.set_aspect('equal')
ax.grid(True, linestyle = '-', color = '0.10')
ax.set_xlim([-15, 15])
ax.set_ylim([-15, 15])
l, = plt.plot([],[], '-', zorder=1)
l2, = plt.plot([],[], '-', zorder=2)
scat = plt.scatter(x, y, c = x, zorder=3)
scat.set_alpha(0.8)
anim = animation.FuncAnimation(fig, _update_plot, fargs = (fig, scat, l,l2),
frames = 720, interval = 10)
plt.show()

Related

How to animate dot over already calculated graph

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
x, y = [], []
line, = plt.plot([], [], 'bo')
circle = plt.Circle((0,0), 1, color = 'g', fill = False,)
def update(frame):
x.append(np.cos(frame))
y.append(np.sin(frame))
line.set_data(x, y)
return circle, line,
ani = FuncAnimation(fig, update, frames= np.linspace(0, 2*np.pi, 128), interval = 0.1)
plt.show()
what I want to animate
I tried to animate uniform circular motion through the code above, but what I can see was only dot moving, not the circle under the dot. How can I plot circle while animating dot?
You can add the circle to the artist with ax.add_artist(circle).
Also, I rewrite the update function so that it only tracks the current dot.
Reference: https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.add_artist.html
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(figsize=(5, 5))
radius = 2
ax.set_xlim(-radius * 1.05, radius * 1.05)
ax.set_ylim(-radius * 1.05, radius * 1.05)
line, = plt.plot([], [], 'bo')
circle = plt.Circle((0, 0), radius, color='k', fill=False)
red_dot = plt.plot(0, 0, 'ro')
ax.set_aspect('equal')
ax.add_artist(circle)
ax.set_axis_off()
def update(i):
theta = np.deg2rad(i)
x = [0, radius * np.cos(theta)]
y = [0, radius * np.sin(theta)]
line.set_data(x, y)
ani = FuncAnimation(fig, update, frames=360, interval=30)
ani.save('fig_1.gif', writer='pillow', fps=45)
plt.show()

Why does my graph not plot the points generated by linspace? (animation)

When I remove linspace and plot points by typing them into a list by hand they are plotted just fine. However switch to linspace, and the points on the graph come up blank. What am I missing here? Printing the linspace lists show they are generating the values, but they don't seem to make the graph
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
%matplotlib qt
fig = plt.figure(figsize=(6,4))
axes = fig.add_subplot(1,1,1)
plt.title("Image That's Moving")
P=np.linspace(1,50,100)
T=np.linspace(1,50,100)
Position =[P]
Time = [T]
p2=[P]
t2=[T]
x,y=[],[]
x2,y2=[],[]
def animate(i):
x.append(Time[i])
y.append((Position[i]))
x2.append(t2[i])
y2.append((p2[i]))
plt.xlim(0,100)
plt.ylim(0,100)
plt.plot(x,y, color="blue")
plt.plot(x2,y2, color="red")
anim = FuncAnimation(fig, animate, interval=300)
It seems like you are facing a problem because of Position = [P] and Time = [T].
Because numpy.linspace already returns an array, you don't need additional [].
Here is a working example that is referenced from matplotlib tutorial.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def init():
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
return ln,
def update(i):
xdata.append(T[i])
ydata.append(P[i])
ln.set_data(xdata, ydata)
return ln,
P = np.linspace(1, 50, 99)
T = np.linspace(1, 50, 99)
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=np.arange(len(T)),
init_func=init, blit=True)
plt.show()
It is not as easy as your written code and, also, not related to np.linspace, AIK. Combining Choi answer (or matplotlib example) with another related SO post we can do this job using some code like:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
def init():
ax1.set_xlim(0, 100)
ax1.set_ylim(0, 100)
ax2.set_xlim(0, 100)
ax2.set_ylim(0, 100)
return ln, ln2
def update(i, Position, Time, P2, T2, ln, ln2):
x.append(Time[i])
y.append(Position[i])
x2.append(T2[i] + 10)
y2.append(P2[i] + 10)
ln.set_data(x, y)
ln2.set_data(x2, y2)
return ln, ln2
Position = P2 = np.linspace(1, 50, 100)
Time = T2 = np.linspace(1, 50, 100)
fig = plt.figure(figsize=(6, 4))
plt.title("Image That's Moving")
plt.xticks([])
plt.yticks([])
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
x, y, x2, y2 = [], [], [], []
ln, = ax1.plot([], [], 'bo')
ln2, = ax2.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=Time.shape[0], fargs=(Position, Time, P2, T2, ln, ln2), init_func=init, blit=True)
ani.save('test.gif', writer='imagemagick', fps=30)

plotting using color as a gradient in matplotlib

I am new to visualization in python. I am trying to plot the same dataset on the left but by using colors as gradient and gridlines to make it understandable. But I'm stuck and I don't know what I did, I just used the reference codes I got from other similar questions. Can someone help out?
import random
import matplotlib
import matplotlib.pyplot as plt
import tkinter as tk
from matplotlib.widgets import Slider
from matplotlib import colors
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import style
import numpy as np
style.use('ggplot')
matplotlib.use('TkAgg')
def update(val):
pos = s_time.val
ax.axis([pos, pos+10, 20, 40])
fig.canvas.draw_idle()
def plot():
canvas = FigureCanvasTkAgg(fig,root)
canvas.get_tk_widget().pack(side=tk.TOP, fill = tk.BOTH, expand =1)
fig.subplots_adjust(bottom=0.25)
y_values = [random.randrange(41) for _ in range(40)]
x_values = [i for i in range(40)]
ax.axis([0, 9, 20, 40])
ax.plot(x_values, y_values)
#cmap = colors.ListedColormap(['red', 'blue','green'])
#bounds = [0,10,20,30]
#norm = colors.BoundaryNorm(bounds, cmap.N)
#ax1.imshow(ax, cmap=cmap, norm=norm)
im0 = ax1.pcolormesh([x_values,y_values], vmin=0, vmax=1, cmap="RdBu")
im = fig.colorbar(im0,cax=ax1)
ax1.grid(which='major', axis='both', linestyle='-', color='white', linewidth=0.5)
#ax1.set_yticks(np.arange(0, 40, 2.5))
ax_time = fig.add_axes([0.12, 0.1, 0.78, 0.03])
return ax_time
root = tk.Tk()
fig = plt.Figure(figsize = (10,10),dpi = 150)
ax=fig.add_subplot(121)
ax1=fig.add_subplot(122)
s_time = Slider(plot(), 'Time', 0, 30, valinit=0)
s_time.on_changed(update)
root.mainloop()
Disclaimer: Not sure if I understood the question correctly. Maybe you could provide links to the reference questions.
If you want to add a color gradient to a lineplot in matplotlib, to my knowledge the best bet is to use ax.scatter. A similar question was asked here:
Matplotlib: different color for every point of line plot
To mimic the appearance of a lineplot you need to interpolate your data linearly before passing it to the scatter function. The c keyword argument can be used to assign a color-value to each data point and the cmap argument determines the actual mapping from color-value to color.
Here is a minimally working example:
import matplotlib.pyplot as plt
import numpy as np
f, ax = plt.subplots(1, 1)
y_values = np.random.randint(0, 41, size=40)
x_values = np.arange(0, 40, 1)
x_interp = np.arange(0, 40, 0.01)
y_interp = np.interp(x_interp, x_values, y_values)
ax.grid(alpha=0.5)
artist = ax.scatter(x_interp, y_interp, c=y_interp, cmap='seismic', lw=0)
f.colorbar(artist, ax=ax)
Which yields the following plot
EDIT:
After clarification I interpret the question as:
"How do I add a background to a lineplot, that shows a color gradient corresponding to the values on the y-axis".
My suggestion is the following:
import matplotlib.pyplot as plt
import numpy as np
f, a = plt.subplots(1, 1)
value_range = (vmin, vmax) = (0, 40)
x_range = (xmin, xmax) = (0, 60)
X, Y = np.meshgrid(range(xmin, xmax, 1), range(vmin, vmax, 1))
y_data = np.random.randint(vmin, vmax, size=xmax-xmin)
x_data = np.arange(xmin, xmax, 1)
a.pcolormesh(Y, cmap="seismic", alpha=0.5, edgecolors='gray')
a.plot(x_data, y_data, "k-")
Which then yields the following plot

3D animation using matplotlib

I want to make 3D animation with matplotlib, but I don't know how to. Here is my non-working code.
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
from math import *
fig = plt.figure()
ax = fig.add_subplot(111) #, projection='3d'
#setting
ax.set_xlim(-5,5)
ax.set_ylim(-5,5)
#ax.set_zlim(-5,5)
ax.set_xlabel('x')
ax.set_ylabel('y')
#ax.set_zlabel('z')
ax.grid()
f1, = ax.plot([], [], "r-", lw=1) #plot1
def gen():
for phi in np.linspace(0,2*pi,100):
yield np.cos(phi), np.sin(phi), phi
def update(data):
p1, q1, psi = data
f1.set_data(p1,q1)
#f1.set_3d_properties(psi)
ani = animation.FuncAnimation(fig, update, gen, blit=False, interval=100, repeat=True)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()
I used this example http://matplotlib.org/1.4.1/examples/animation/simple_3danim.html
and modified your code:
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
def gen(n):
phi = 0
while phi < 2*np.pi:
yield np.array([np.cos(phi), np.sin(phi), phi])
phi += 2*np.pi/n
def update(num, data, line):
line.set_data(data[:2, :num])
line.set_3d_properties(data[2, :num])
N = 100
data = np.array(list(gen(N))).T
line, = ax.plot(data[0, 0:1], data[1, 0:1], data[2, 0:1])
# Setting the axes properties
ax.set_xlim3d([-1.0, 1.0])
ax.set_xlabel('X')
ax.set_ylim3d([-1.0, 1.0])
ax.set_ylabel('Y')
ax.set_zlim3d([0.0, 10.0])
ax.set_zlabel('Z')
ani = animation.FuncAnimation(fig, update, N, fargs=(data, line), interval=10000/N, blit=False)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()
Here is the following code for a sphere moving to the right and off the screen.
You will have to run this code in a folder for tidiness, as it generates 26 .png images (and a .gif image):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from numpy import sin, cos, pi, outer, ones, size, linspace
# Define x, y, z lists for sphere
a = linspace(0, 2 * pi)
b = linspace(0, pi)
x = 10 * outer(cos(a), sin(b))
y = 10 * outer(sin(a), sin(b))
z = 10 * outer(ones(size(a)), cos(b))
# The amount of frames in the animation
frames = 26
# Generate each frame
for n in range(frames):
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, color=('b'))
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
plt.savefig(f"{n}.png")
plt.close()
# Add 1 to the x so the sphere moves right by 1
x += 1
# Use pillow to save all frames as an animation in a gif file
from PIL import Image
images = [Image.open(f"{n}.png") for n in range(frames)]
images[0].save('ball.gif', save_all=True, append_images=images[1:], duration=100, loop=0)
Output:

Stop matplotlib plot from closing

I have code for "live" plotting with Matplotlib in Python, but it closes once it's done. I would like the plot to remain open.
Code below
import time
import matplotlib.pyplot as plt
plt.ion()
plt.show()
for i in range(10):
time.sleep(1)
x = i ** 2
plt.scatter(i, x)
plt.draw()
Maybe you want something like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def make_data():
for i in range(100):
yield i, i*2
fig, ax = plt.subplots()
color = plt.cm.cubehelix(np.linspace(0.1,0.9,100))
plot, = ax.plot([], [],'o')
xdata, ydata = [], []
ax.set_ylim(0, 1)
ax.set_xlim(0, 1)
def run(data):
x,y = data
xdata.append(x)
ydata.append(y)
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
if y > ymax:
ax.set_xlim(xmin, 1+xmax)
ax.set_ylim(ymin, 1+ymax)
ax.figure.canvas.draw()
plot.set_color(color[x])
plot.set_data(xdata,ydata)
return plot,
ani = animation.FuncAnimation(fig,run,make_data,blit=True,interval=10,repeat=False)
plt.show()
Maybe scatter would be better since it might allow for different colors of each circle.

Categories

Resources