multiprocessing show matplotlib plot - python-3.x

I'm trying to open up multiple plots but I ran into a few problems. When I tried to create plots using threading, python would first open a number of windows, then close all but the first.
In another question it was recommended that I use multiprocessing which I have tried. The code runs without error, it just doesn't show any plot.
I'm trying to get something very simple to work before moving on to my main project.
# Import the necessary packages and modules
import matplotlib.pyplot as plt
import numpy as np
#from threading import Thread
import multiprocessing
def plot(datax, datay, name):
# Prepare the data
x = datax
y = datay**2
# Plot the data
plt.scatter(x, y, label=name)
# Add a legend
plt.legend()
# Show the plot
plt.show()
#plot(3,3,)
'''
for i in range(10):
t = Thread(target=plot, args=(i,i+1,i,))
t.start()
'''
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
update:
for some reason, multiprocessing stopped working again. I tried creating a function multiP() only to open the processes but it didn't work when I added the input('value: '). scine I can't figure out how to send data to a specific thread I'm going to save data like this: dat = [[x,y0,y1,...yn],[x,y0,y1,...yn],...] and each plot process with check the if something was added to dat.
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows
def plot(datax, datay, name):
x = datax
y = datay**2
plt.scatter(x, y, label=name)
plt.legend()
plt.show()
def multiP():
if __name__ == "__main__":
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
if True:
#input('Vlaue: ') # while commented plots are shown
multiP()

The following code produces two figures as desired.
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows
def plot(datax, datay, name):
x = datax
y = datay**2
plt.scatter(x, y, label=name)
plt.legend()
plt.show()
def multiP():
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
if __name__ == "__main__":
input('Value: ')
multiP()

Taking ImportanceOfBeingErnest answer, I leave below an implementation which only shows one window and waits for the window to close, which can be very handy. Every time it is called, it displays a new window with the corresponding image (a new pocess will be started for each image). I used a lot to view images when stopped at some breakpoint during debug.
# Library packages needed
import numpy as np
import datetime
import sys
import queue
import multiprocessing
# Plot related packages
import matplotlib.pyplot as plt
def showImage(img: np.ndarray, title: str = str(datetime.datetime.today())):
"""Show an image in a new process without blocking. Usefull for debugging.
Args:
img (np.ndarray): Image to be shown
title (str, optional): Title to be shown. Defaults to
str(datetime.datetime.today()).
"""
def plot(q, title):
fig = plt.figure()
fig.suptitle(title)
try:
q.get(True, 2.0) # Wait a couple of seconds
except queue.Empty:
print('Not image received to plot...quitting')
sys.exit()
plt.imshow(img)
plt.show()
sys.exit()
# Create a queue to share data between process
q = multiprocessing.Queue()
# Create and start the process
proc = multiprocessing.Process(None, plot, args=(q, title))
proc.start()
q.put(img)
To run it, just save this to a show_image.py file and call
from show_image.py import showImage
show_image(img, title)

Related

Plotting matplotlib figure through a class doesn't work

I created a class "Plot" for matplotlib plot objects. Running the following code neither shows error nor outputs anything. Any help is much appreciated.
import matplotlib.pyplot as plt
class Plot:
def __init__(self):
self.fig = plt.figure()
self.ax = self.fig.add_subplot()
def create_plot_background(self):
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
x, y = [range(10), range(10)]
p = Plot()
p.create_plot_background()
p.ax.plot(x, y)
p.fig.show()

python real time plot using funcanimation giving blank graph

I am trying to plot a realtime graph using matplotlib's FuncAnimation class. The data is coming from arduino using pyserial library. I have tried the following code to plot in real time but the graph is empty, I can see the axes, ticks etc but not the plot. Can anyone help me what I am doing wrong here?
Thank you in advance.
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import serial
import os
import numpy as np
import datetime
import pandas as pd
fig = plt.figure()
port= 'COM10'
baudrate = 9600
timeout = 2
ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout)
def animate(i):
j = 0
while True:
try:
loadcells = ser.readline()
loadcells = loadcells.decode('utf-8').rstrip().replace('\t','').split(',')
print(loadcells)
loadcell1 = float(loadcells[0])
# loadcell2 = loadcells[1]
plt.cla()
plt.plot(loadcell1)
plt.pause(0.001)
j+=1
# plt.plot(loadcell2)
except Exception as e:
print(e)
continue
except KeyboardInterrupt as e1:
print(e1)
ser.close()
anim = FuncAnimation(fig, animate,
frames = 200,
interval = 0.1,
blit = False)
plt.tight_layout()
plt.show()
You should not have an infinite loop in animate(). FuncAnimation works by calling animate() repeatedly at a pre-defined interval (interval=0.1).
You need to rewrite your animate() function where you read the serial port, plot the result, and return (no pause() either).

module '<file_name>' has no attribute '__path__'

I'm using commands on terminal to run this script (plot_test.py is the name of the file):
#python3
import pybullet as p
import pybullet_data as p_data
import time
import matplotlib.pyplot as plt
import numpy as np #to reshape for matplotlib
import os
import matplotlib.animation as animation
# os.environ['MESA_GL_VERSION_OVERRIDE'] = '3.3'
# os.environ['MESA_GLSL_VERSION_OVERRIDE'] = '330'
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
# plt.ion()
# GUI = 0
def animate(i):
graph_data = open('solved_states.bin','r').read()
lines = graph_data.split('\n')
time_stamp = [] #time
torque = [] #torque
for line in lines:
if len(line) > 1:
x, y = line.split(',')
time_stamp.append(float(y))
torque.append(float(x))
ax1.clear()
ax1.plot(time_stamp, torque,color='r',label='Torque')
ax1.set_title('Torque Vs Time')
ax1.set_xlabel('Time')
ax1.set_ylabel('Torque')
ax1.legend(loc="upper right")
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Altough it plots the graph and, I keep getting this error:
pybullet build time: Oct 8 2020 00:10:04
/usr/bin/python3: Error while finding module specification for 'plot_test.py' (AttributeError: module 'plot_test' has no attribute '__path__')
I'm new to python and I don't know how this works
I've seen similar questions like this before, but here, the file that I am working on is showing up the error.
Are you running the file with command
python -m plot_test.py
?
The flag -m runs the file as a module and then you need to omit the .py
If my assumption is true then you should be good with either:
python -m plot_test
or simply
python plot_test.py

Matplotlib.animation.FuncAnimation using pcolormesh

Python 3.5, windows 10 Pro.
I'm trying to continuously plot an 8x8 array of pixels (for the sake of the question I'll just use random data, but in the real thing I'm reading from a serial port).
I can do it using a while loop, but I need to switch over to matplotlib.animation.FuncAnimation and I can't get it to work. I've tried looking at the help files and tried to follow examples from matplotlib.org here, but I've not been able to follow it.
Can someone help me figure out how to continuously plot an 8x8 array of pixels using FuncAnimation and pcolormesh? Here is what I've got so far:
import scipy as sp
import matplotlib.pyplot as plt
from matplotlib import animation
plt.close('all')
y = sp.rand(64).reshape([8,8])
def do_something():
y = sp.rand(64).reshape([8,8])
fig_plot.set_data(y)
return fig_plot,
fig1 = plt.figure(1,facecolor = 'w')
plt.clf()
fig_plot = plt.pcolormesh(y)
fig_ani = animation.FuncAnimation(fig1,do_something)
plt.show()
If you want to see the while loop code, just so you know exactly what I'm trying to reproduce, see below.
import scipy as sp
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
while True:
y = sp.rand(64).reshape([8,8])
plt.pcolormesh(y)
plt.show()
plt.pause(.000001)
I was able to find a solution using imshow instead of pcolormesh. In case anyone else is struggling with the same issues I had, I've posted the working code below.
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Hz = sp.rand(64).reshape([8,8]) # initalize with random data
fig = plt.figure(1,facecolor='w')
ax = plt.axes()
im = ax.imshow(Hz)
im.set_data(sp.zeros(Hz.shape))
def update_data(n):
Hz = sp.rand(64).reshape([8,8]) # More random data
im.set_data(Hz)
return
ani = animation.FuncAnimation(fig, update_data, interval = 10, blit = False, repeat = False)
fig.show()

Improve speed of resizing plot (matplotlib) inside GTK-window

I have some heavy plot and it's ok that it calculating couple seconds, but when i resize window/chart - its hang up for some time and that is not obviously behavior for me. How i can fix this? There is no changes in plot data, just resizing.
Demo:
import numpy as np
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import matplotlib
matplotlib.use('GTKCairo')
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
class MyApp:
def __init__(self):
self.Window = Gtk.Window()
graphFig = Figure()
graphCanvas = FigureCanvas(graphFig)
self.Window.add(graphCanvas)
# just example of heavy chart
subplot = graphFig.add_subplot(111)
for n in range(100):
x = np.arange(0, 100, 0.01)
y = np.sin(x) * n
subplot.plot(x, y)
return
def Run(self):
self.Window.show_all()
Gtk.main()
return
App = MyApp()
App.Run()
What options exist of fixing this issue? I wanna redraw chart only when its updated or when user pan/zoom it.
To speed up plotting, consider plotting lower resolution lines. 100 lines at 1000 samples each is a lot of drawing.
Barring that, this post has a very detailed answer that could help you improve speed.

Resources