1

I have two processes that communicate via sockets. The first process first opens the second process in the following way:

def run_command(cmd)
    subprocess.call(cmd, shell=True)

cmd = 'python full_path_to_script.py'
thread = Thread(target=run_command, args=(cmd,)
thread.start()

And then opens the connection:

from multiprocessing.connection import Client
address = ('localhost', port_number)
conn = Client(address, authkey=b'some_password')

When the first want to plot something, it sends a message to the second one, which decipher the message and plot the data using matplotlib. The idea is that the first message opens an image, and the other messages send updates to the image. The problem is that pyplot.show hangs the second process which now cannot get new messages. I tried to use pyplot.ion() but then the figure just got frozen (it didn't help to add pyplot.pause(0.001)).

Noam Peled
  • 4,484
  • 5
  • 43
  • 48

2 Answers2

2

It is hard to tell exactly what you are doing without seeing the code, but I think that this is the expected and correct behavior.

If you use plt.show without interactive mode on what is happening is that the GUI event loop is getting control of the thread in your sub-process. This event loop is what takes in the mouse/keyboard events to make the graph interactive. Hence, so long as that window is open the GUI controls the main thread of your second process and it will seem to ignore your other messages.

Alternatively, when you use plt.ion() the GUI event loop does not run, but instead relies on something else to periodically kick it (at the command prompt this is done via the PyOS_InputHook mechanism) so although your second process is getting your messages, nothing is shown (as the GUI event loop has not run to re-paint the window) and the window seems dead (because the event loop is not consuming the input events).

You either need to roll you own event loop in the second process (as you are implementing RPC, not a bad idea) and periodically call canvas.flush_events (which will run the event loop until all pending events are exhausted), have the GUI framework handle getting the events from the lead process, on (maybe) push that message handling on the follower process off to a sub-thread (if you do this be very careful to only use draw_idle to request a figure re-draw, GUIs do not like you trying to draw from not the main thread).

tacaswell
  • 84,579
  • 22
  • 210
  • 199
1

I used the pyqtgraph lib to continuously plot values that I received from a COM port running under Windows as I could never get matplotlib to update reliably in real-time despite hours of trying. pyqtgraph comes with a good example file which I used as a template and then could modify for my use case, this I got to work reliably after quite few tries.

So I had

  • one python thread reading the COM port in a while loop, this thread filled a deque at one end and popped an element at the other.
  • the deque was then copied to the graph every 20 ms or so in the graph update function.
Adam.at.Epsilon
  • 263
  • 2
  • 12