Socket communication and realtime plotting

I have two processes on my machine with one-way socket communication.
One process generates data, the other plots it.
I have figured out the data transfer part, but have not been able to display/update the data.

A MWE is below.
When run on macOS Sierra, I don’t even see a TCanvas appear. On OS X 10.11 (El Capitan), the TCanvas does display, but the TGraph does not.

Data generator/transmitter

import socket
import pickle
import time

pickleSep = ':::::'

HOST = 'localhost'
PORT = 32768
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind( (HOST,PORT) )
print "Binded to PORT", PORT
server_sock.listen(1)
ROOT_sock, addr = server_sock.accept()
print 'Connected by', addr

for ii in range(100):
    print "ii = ", ii
    toSend = pickle.dumps(('testing', (ii, ii,ii*ii))) + pickleSep
    ROOT_sock.sendall(toSend)
    time.sleep(0.2)

Data receiver/plotter

import ROOT
import pickle
import socket

HOST = 'localhost'    # The remote host
PORT = 32768          # The same port as used by the server 
pickleSep = ':::::'

# ========================= 
# Initialize the ROOT plots
# =========================
cc = ROOT.TCanvas('cc','Apollo Plots', 960, 720)
ROOT.SetOwnership(cc, False)
pad1 = ROOT.TPad("test_name","test_title", 0.3, 0.3, 0.8, 0.8)
pad1.Draw()
pad1.cd()
ROOT.SetOwnership(pad1, False)
g1 = ROOT.TGraph()

# ==============================
# Set up the socket connection
# ==============================
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect( (HOST,PORT) )

# ====================
# Handle incoming data
# ====================
while True:
    pickled_data = s.recv(4096)
    pickled_data = pickled_data.split(pickleSep)

    for each in pickled_data:
        if len(each) > 0:
            data = pickle.loads(each)
            print "data = ", data
            if data[0] == 'testing':
                vals = data[1]
                pad1.cd()
                g1.SetPoint(vals[0], vals[1], vals[2])
                pad1.Modified()
                cc.Update()

ROOT.gSystem.ProcessEvents()
ROOT.gApplication.Run()

Have you tried to write your plotting process in C++ instead of Python ?

No, not yet. I would need to sort out the socket communications on the C++ side. Is there a known issues on the pyROOT side that would prevent this from working?

I am not sure, I am not a regular user of Python. I know it would work with C++.

I found the (simple) mistake. The transmit code was fine as-is. In the receive code, however, I never called g1.Draw()… Also, I had ROOT.gSystem.ProcessEvents() outside of the loop.

Here’s the working code for the receiver:

import ROOT
import pickle
import socket

HOST = 'localhost'    # The remote host
PORT = 32768          # The same port as used by the server
pickleSep = ':::::'

# =========================
# Initialize the ROOT plots 
# =========================
cc = ROOT.TCanvas('cc','Apollo Plots', 960, 720)
ROOT.SetOwnership(cc, False)
pad1 = ROOT.TPad("test_name","test_title", 0.3, 0.3, 0.8, 0.8)
pad1.Draw()
pad1.cd()
ROOT.SetOwnership(pad1, False)
g1 = ROOT.TGraph()
pad1.cd()
g1.Draw("alp")

# ==============================
# Set up the socket connection
# ==============================
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect( (HOST,PORT) )

# ====================
# Handle incoming data
# ====================
while True:
    pickled_data = s.recv(4096)
    pickled_data = pickled_data.split(pickleSep)
    ROOT.gSystem.ProcessEvents()
    for each in pickled_data:
        if len(each) > 0:
            data = pickle.loads(each)
            print "data = ", data
            if data[0] == 'testing':
                vals = data[1]
                g1.SetPoint(vals[0], vals[1], vals[2])
                pad1.Modified()
                cc.Update()


ROOT.gApplication.Run()