Python: GUI - plotting, reading from pixels in real-time GUI - python

I've got a project in the works. I'm a rookie, roommate is a software engineer and suggested I used python for this project. My questions are listed below. first, here is an overview of what I am attempting to accomplish.
project overview:
An array of addressable RGB led matrices, say, 50 leds x 50 leds (250
leds). The led matrix is connected to and ran by an arduino which
will receive the matrix's pattern information from a decentralized
program. (We'll worry about the arduino's function later)
The purpose of the program is to generate and send pattern information
for each addressable LED to the arduino.
The program will host a GUI in order to alter and visualize the
outgoing or current matrix colormap and pattern in real-time (ie. turn on/off
strobe effect, turn on/off fade effect). The program will then read
from the gui to generate and translate RGB values to send to the
arduino.
Here is where I am at, and I need guidance. As of now, I am focusing on getting the GUI to work properly before moving on to the next parts of this project.
I'm using matplotlib in hopes that I can create a plot of 50x50 squares (or pixels) and retain control over each individuals point's value and struggling greatly. Ideally, I would be able to draw to the plot 30 times a second, or however many times so that it would appear to be updating in "real-time".
Here is some sample code so you can get a better understanding of what I am trying to accomplish:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import cm
from numpy.random import random
fig = plt.figure()
matrix = random((50,50))
plt.imshow(matrix, interpolation='nearest', cmap=cm.spectral)
def update(data):
print("IN UPDATE LOOP")
matrix = random((50,50))
return matrix
def data_gen():
print("IN DATA_GEN LOOP")
while True: yield np.random.rand(10)
ani = animation.FuncAnimation(fig, update, data_gen, interval=1000)
plt.imshow(matrix, interpolation='nearest', cmap=cm.spectral)
plt.show()
plt.draw()
Photo of matrix with random values assigned to each square
Grid won't update, not sure why...
Why is my grid not updating?

Ignoring the first two questions as they are not really on topic here, the problem with the code is that you never actually update the image. This should be done in the animating function.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import cm
from numpy.random import random
fig = plt.figure()
matrix = random((50,50))
im = plt.imshow(matrix, interpolation='nearest', cmap=cm.Spectral)
def update(data):
im.set_array(data)
def data_gen():
while True:
yield random((50,50))
ani = animation.FuncAnimation(fig, update, data_gen, interval=1000)
plt.show()

Related

Matplotlib Imshow Doesn't Update With Draw

I'm having trouble getting imshow to update with new data. For reference I'm pulling data off a serial port and trying to plot it, updating every second or so. I had been accumulating the data with a thread, so I initially thought that might be the problem as matplotlib isn't thread safe. However, I can't get the following simpler example to work:
import numpy as np
import matplotlib.pyplot as plt
import time
dat = np.random.rand(100,10)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
image = ax.imshow(np.zeros((10,10)))
fig.canvas.draw()
count = 0
while count < 100:
image.set_data(dat[count:count+10])
fig.canvas.draw()
count += 10
time.sleep(1)
Using TkAgg, I just get the plot of all zeros, it never updates then quits.
With Qt5Agg, an empty window pops up before quitting.
I've tried various combinations of draw_idle(), flush_events() and plt.show(block=False), with the same results.
python 3.8.10 , matplotlib 3.2.2
Immediately after posting this I figured out the solution.
I initialized the plot with all zeros - changing this to be a random array of values fixes it fixes it.
I'm not sure why starting with all zeros broke the color scaling, though from the matplotlib documentation the default normalization scales the input data on [0,1], so I suspect that was the issue.

Problem trying to animate Brownian Motion with matplotlib

Im really new in programming with Python and in my final project I need to create this animation where 10 points are randomly moving in space (Brownian motion).
My teacher gave me some examples but I just cant figure out why my program is not working correctly. The error says:
"_included_frames frame_dir=os.path.dirname(frame_list[0]),
IndexError: list index out of range"
Sorry if I didnĀ“t express myself correctly but also English is not my native language.
from math import *
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
import matplotlib.animation as animation
fig = plt.figure()
ax = plt.axes(projection='3d')
N=10
x=500*np.random.random(N)
y=500*np.random.random(N)
z=500*np.random.random(N)
def frame(w):
ax.clear()
x=x+np.random.normal(0.0,50.0,10)
y=y+np.random.normal(0.0,50.0,10)
z=z+np.random.normal(0.0,50.0,10)
mensaje="Movimiento Browniano"
plt.title(mensaje)
ax.set_xlim3d(-500.0,500.0)
ax.set_ylim3d(-500.0,500.0)
ax.set_zlim3d(-500.0,500.0)
plot=ax.scatter3D(x, y, z, c='r')
return plot
anim = animation.FuncAnimation(fig, frame, frames=100, blit=False)
anim.save( 'MovimientoBrowniano.html', fps=5 )
There are two main problems with your code.
x,y and z are attempted to be changed locally in your function. However you really want to change the variables defined outside of the function scope. You may easily do that by declaring them globally: Add global x,y,z in your function.
You are trying to save the animation to an html file. That is no valid video format. I don't know which format you are targeting here, but a common option would be an animated gif, which could be produced by
anim.save('MovimientoBrowniano.gif', writer = "pillow", fps=5 )

Live plotting on bloch sphere

I am trying to plot live data on a bloch sphere using Qutip's function bloch().
So far, the code always interrupts, when I have a b.show() in there.
I found a lot of solutions online to similar problems, but most of them make use of direct matplotlib commands like matplotlib.draw() which doesn't seem to work with the bloch class.
Then, there are other solutions which make use of for example Tk or GTKagg (e.g. https://stackoverflow.com/a/15742183/3276735 or real-time plotting in while loop with matplotlib)
Can somebody please help me how to deal with the same problem in the bloch class?
Edit:
Here's a minimal example:
Basically, I want to update my plot with one point at a time, preferably in a loop. My goal is to display live data in the plot that has to be read from a file.
import qutip as qt
import numpy as np
b = qt.Bloch()
theta = np.arange(0,np.pi,0.1)
for ii in range(len(theta)):
b.add_points([np.sin(theta[ii]),0,np.cos(theta[ii])])
b.show()
I think you are breaking your plot because you are calling show for every point. Try calling show outside the loop (in the end).
import qutip as qt
import numpy as np
b = qt.Bloch()
theta = np.arange(0,np.pi,0.1)
for ii in range(len(theta)):
b.add_points([np.sin(theta[ii]),0,np.cos(theta[ii])])
b.show() # Changed here
EDIT: Animated plot
Consider show as an absolute command to call the plot into view. It's not a draw command (or redraw). If you do want to show an image every "n" seconds or so you'll need to clear the plot before calling it again. You may try this:
import qutip as qt
import numpy as np
b = qt.Bloch()
theta = np.arange(0,np.pi,0.1)
for ii in range(len(theta)):
b.clear()
b.add_points([np.sin(theta[ii]),0,np.cos(theta[ii])])
b.show()
# wait time step and load new value from file.
, I don't have QuTip in my current distribution so I can't really test it but I'm betting its heavily based in matplotlib. My best advise however is for you to use the formulation give for animation in the QuTiP docs. By following this recipe:
from pylab import *
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
fig = figure()
ax = Axes3D(fig,azim=-40,elev=30)
sphere=Bloch(axes=ax)
def animate(i):
sphere.clear()
sphere.add_vectors([sin(theta),0,cos(theta)])
sphere.add_points([sx[:i+1],sy[:i+1],sz[:i+1]])
sphere.make_sphere()
return ax
def init():
sphere.vector_color = ['r']
return ax
ani = animation.FuncAnimation(fig, animate, np.arange(len(sx)),
init_func=init, blit=True, repeat=False)
ani.save('bloch_sphere.mp4', fps=20, clear_temp=True)
, you should be able to modify the animate function to perform all operations you need.

Combining mayavi and matplotlib in the same figure

I will be making animations. In each frame I want to contain both a mayavi plot obtained with
mlab.pipeline.iso_surface(source, some other superfluous args)
and a matplotlib plot obtained using simply
pylab.plot(args)
I have scripts to do both separately, but have no idea how to go about combining them into one figure. I want the end product to be one script which contains the code from both the scripts that I currently have.
AFAIK, there is no direct way because the backends used are so different. It does not seem possible to add matplotlib axes to mayavi.figure or vice versa.
However, there is a "kind of a way" by using the the mlab.screenshot.
import mayavi.mlab as mlab
import matplotlib.pyplot as plt
# create and capture a mlab object
mlab.test_plot3d()
img = mlab.screenshot()
mlab.close()
# create a pyplot
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.plot([0,1], [1,0], 'r')
# add the screen capture
ax2 = fig.add_subplot(122)
ax2.imshow(img)
ax2.set_axis_off()
This is not necessarily the nicest possible way of doing things, and you may bump into resolution problems, as well (check the size of the mayavi window). However, it gets the job done in most cases.
Adding to the answer by DrV which helped me a great deal, you can work with the mlab figure to set resolution before screenshot such as with batch plotting:
mfig = mlab.figure(size=(1024, 1024))
src = mlab.pipeline.scalar_field(field_3d_numpy_array)
mlab.pipeline.iso_surface(src)
iso_surface_plot = mlab.screenshot(figure=mfig, mode='rgba', antialiased=True)
mlab.clf(mfig)
mlab.close()
# Then later in a matplotlib fig:
plt.imshow(iso_surface_plot)

Step by step showing 2D/3D add/remove points

I'm writing some python functions that deals with manipulating sets of 2D/3D coordinates, mostly 2D.
The issue is debugging such code is made difficult just by looking at the points. So I'm looking for some software that could display the points and showing which points have been added/removed after each step. Basically, I'm looking for a turn my algorithm into an animation.
I've seen a few applets online that do things similar what I was looking for, but I lack the graphics/GUI programming skills to write something similar at this point, and I'm not sure it's wise to email the authors of things whose last modified timestamps reads several years ago. I should note I'm not against learning some graphics/GUI programming in the process, but I'd rather not spend more than 1-3 days if it can't be helped, although such links are still appreciated. In this sense, linking to a how-to site for writing such a step-by-step program might be acceptable.
With the matplotlib library it is very easy to get working animations up. Below is a minimal example to work with. The function generate_data can be adapted to your needs:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def generate_data():
X = np.arange(25)
Y = X**2 * np.random.rand(25)
return X,Y
def update(data):
mat[0].set_xdata(data[0])
mat[0].set_ydata(data[1])
return mat
def data_gen():
while True:
yield generate_data()
fig, ax = plt.subplots()
X,Y = generate_data()
mat = ax.plot(X,Y,'o')
ani = animation.FuncAnimation(fig, update, data_gen, interval=500,
save_count=10)
ani.save('animation.mp4')
plt.show()
This example was adapted from a previous answer and modified to show a line plot instead of a colormap.

Categories

Resources