4

I am a poor programmer so please excuse my simple question. I am trying to build a little program that reads data from the serial interface and displays it on the screen. I have been able to do this in iPython notebook and matplotlib and I have been able to add buttons to the screen that control data requests that go to the interface: Button click -> ser.write, ser.read, draw

I am now struggling to design the program such that pressing a button will start repeated data collection in fixed time steps until the button is toggled off again. Can someone please help me out with a sketch for such a program?

So far:

%pylab 

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Button

import serial
import binascii
import struct
from time import sleep

fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.2)
ax.axis([0, 10, 0, 255])

ser = serial.Serial('COM5', 1000000, timeout=0) 
ser.write("0".encode())
sleep(0.1)
if ser.read()== b'\xf1':
    print ("Interface is responding")
else:
    print ("Interface is NOT responding")
    ser.flush()
    ser.close()
    exit(1)

t = np.linspace(0, 10, 2048)
line1, line2 = plt.plot(t,0*t, t,0*t, lw=2)

def ShowChannel(Channel):
    if Channel==1:
        ser.write("11".encode())
    elif Channel==2:
        ser.write("12".encode())
    sleep(0.05)
    Header = ser.read().decode("utf-8")
    # print(Header)
    if Header == "1":
        data = ser.read(2048)
        y = struct.unpack('2048B', data)
        # print(y)
        if Channel==1:
            line1.set_ydata(y)
        elif Channel==2:
            line2.set_ydata(y)
        fig.canvas.draw()

def one(event):
    ShowChannel(1)

def two(event):
    ShowChannel(2)

axone = plt.axes([0.1, 0.05, 0.1, 0.075])
axtwo = plt.axes([0.21, 0.05, 0.1, 0.075])
axstart = plt.axes([0.40, 0.05, 0.1, 0.075])
axstop = plt.axes([0.51, 0.05, 0.1, 0.075])

bone = Button(axone, '1')
bone.on_clicked(one)
btwo = Button(axtwo, '2')
btwo.on_clicked(two)

Following the example cited in the comments, I added the following

# Build check button axes
rax = plt.axes([0.7, 0.05, 0.1, 0.1], aspect='equal')
labels = ('go!',)
check = CheckButtons(rax, labels, (False, ))

KeepShowing = False

def func(event):
    global KeepShowing
    KeepShowing = not KeepShowing
#    print(event, KeepShowing)

check.on_clicked(func)

while True:
    if KeepShowing:
        ShowChannel(1)
    sleep(1)

But the loop at the bottom is not how to do it. When I start the program with it, the graphics window opens, but doesn't show anything. Only if I interrupt the kernel in ipython the screen builds.

4
  • Can you edit your question to include the code you've written so far? Commented Apr 25, 2015 at 15:07
  • I was expecting a while loop -- in prose, "while the button-state is ON, (read, plot, wait a few seconds, repeat)". Pressing the button would toggle the button-state between ON and OFF. (Or use a radio-button or such that's inherently one of ON/OFF.) Commented Apr 25, 2015 at 22:37
  • @cphlewis Well, I tried that, but didn't work. I somehow don't get the concept of callbacks. When I send the program to loop, the whole thing freezes and doesn't want to listen to buttons anymore. When I manually break the loop, the buttons can be used again. Commented Apr 25, 2015 at 23:49
  • The checked_buttons example doesn't even use callbacks (explicitly). Commented Apr 26, 2015 at 0:03

1 Answer 1

2

If you want to call the function which reads the data routinely, you can use the timer in matplotlib module. The code is as following:

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
timer = fig.canvas.new_timer(interval)
timer.add_callback(function, args)

The unit of the interval is ms, and you can use the timer.start() or timer.stop() methods to turn on or turn off the timer.


Based on your code, I add the timers for each button and add variables to check whether the timers are running:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Button

import serial
import binascii
import struct
from time import sleep

fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.2)
ax.axis([0, 10, 0, 255])

ser = serial.Serial('COM5', 1000000, timeout=0) 
ser.write("0".encode())
sleep(0.1)
if ser.read()== b'\xf1':
    print ("Interface is responding")
else:
    print ("Interface is NOT responding")
    ser.flush()
    ser.close()
    exit(1)

t = np.linspace(0, 10, 2048)
line1, line2 = plt.plot(t,0*t, t,0*t, lw=2)

def ShowChannel(Channel):
    if Channel==1:
        ser.write("11".encode())
    elif Channel==2:
        ser.write("12".encode())
    sleep(0.05)
    Header = ser.read().decode("utf-8")
    # print(Header)
    if Header == "1":
        data = ser.read(2048)
        y = struct.unpack('2048B', data)
        # print(y)
        if Channel==1:
            line1.set_ydata(y)
        elif Channel==2:
            line2.set_ydata(y)
        fig.canvas.draw()

def one(event):
    global channel1_on

    if channel1_on == 0:
        channel1_on = 1
        timer1.start()
    else:
        channel1_on = 0
        timer1.stop()
        line1.set_ydata(None)

def two(event):
    global channel2_on

    if channel2_on == 0:
        channel2_on = 1
        timer2.start()
    else:
        channel2_on = 0
        timer2.stop()
        line2.set_ydata(None)

channel1_on = 0
channel2_on = 0
timer1 = fig.canvas.new_timer(interval = 50)
timer1.add_callback(ShowChannel, 1)
timer2 = fig.canvas.new_timer(interval = 50)
timer2.add_callback(ShowChannel, 2)

axone = plt.axes([0.1, 0.05, 0.1, 0.075])
axtwo = plt.axes([0.21, 0.05, 0.1, 0.075])
axstart = plt.axes([0.40, 0.05, 0.1, 0.075])
axstop = plt.axes([0.51, 0.05, 0.1, 0.075])

bone = Button(axone, '1')
bone.on_clicked(one)
btwo = Button(axtwo, '2')
btwo.on_clicked(two)

plt.show()

Another one thing is if I did not add the line plt.show() in your code, it did not show the figure when it ran in my computer. So I add it in the end of your code and it can show the figure now.

Hope it helps.

Sign up to request clarification or add additional context in comments.

1 Comment

yup, this timer thingy does it! Thx 1m

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.