使用Button Jupyter Notebook终止循环? [英] Kill a loop with Button Jupyter Notebook?

查看:0
本文介绍了使用Button Jupyter Notebook终止循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想:

  • 从串口读取(无限循环)
  • 按下停止按钮时-->;停止读取并绘制数据

How to kill a while loop with a keystroke?开始,我举了一个使用键盘中断的例子,可以使用,但我想使用按钮。

键盘中断示例

weights = []
times = [] 
#open port 
ser = serial.Serial('COM3', 9600)
try:
   while True: # read infinite loop
       #DO STUFF
       line = ser.readline()   # read a byte string
       if line:
           weight_ = float(line.decode())  # convert the byte string to a unicode string
           time_ = time.time()
           weights.append(weight_)
           times.append(time_)
           print (weight_)
#STOP it by keyboard interup and continue with program 
except KeyboardInterrupt:
   pass
#Continue with plotting

不过,我希望使用显示的按钮(更便于人们使用)。 我曾尝试制作一个按钮(在Jupiter Notebook中),当按下Break_Cicle=False时,循环不会在按下按钮时中断

 #make a button for stopping the while loop 
button = widgets.Button(description="STOP!") #STOP WHEN THIS BUTTON IS PRESSED
output = widgets.Output()
display(button, output)
break_cicle=True


def on_button_clicked(b):
    with output:
        break_cicle = False # Change break_cicle to False
        print(break_cicle)
        
ser.close()   
button.on_click(on_button_clicked)
ser = serial.Serial('COM3', 9600)
try:
    while break_cicle:

        print (break_cicle)
        line = ser.readline()   # read a byte string
        if line:
            weight_ = float(line.decode())  # convert the byte string to a unicode string
            time_ = time.time()
            weights.append(weight_)
            times.append(time_)
            print (weight_)
except :
    pass

ser.close()    

全局不工作的示例

from IPython.display import display
import ipywidgets as widgets

button = widgets.Button(description="STOP!") #STOP WHEN THIS BUTTON IS PRESSED
output = widgets.Output()
display(button, output)
break_cicle=True

def on_button_clicked():
    global break_cicle #added global
    with output:
        
        break_cicle = False # Change break_cicle to False
        print ("Button pressed inside break_cicle", break_cicle)
    
    
button.on_click(on_button_clicked)
try:
    while break_cicle:
        print ("While loop break_cicle:", break_cicle)
        time.sleep(1)
except :
    pass
print ("done")

尽管我按了几次按钮,但从下图中您可以看到它从未打印过BREAK_CICLE"ON内部按下的&QUTON。

推荐答案

我认为问题就像所有具有长时间运行代码的Python脚本一样--它在一个线程中运行所有代码,当它运行while True循环(长时间运行代码)时,它无法同时运行其他函数。

您可能必须在单独的线程中运行函数,然后主线程才能执行on_button_clicked

此版本适用于我:

from IPython.display import display
import ipywidgets as widgets
import time
import threading

button = widgets.Button(description="STOP!") 
output = widgets.Output()

display(button, output)

break_cicle = True

def on_button_clicked(event):
    global break_cicle
    
    break_cicle = False

    print("Button pressed: break_cicle:", break_cicle)
    
button.on_click(on_button_clicked)

def function():
    while break_cicle:
        print("While loop: break_cicle:", break_cicle)
        time.sleep(1)
    print("Done")
    
threading.Thread(target=function).start()

也许Jupyter有其他方法来解决这个问题--即。当您使用async编写函数时,您可以使用asyncio.sleep(),它允许在其他函数处于休眠状态时运行该函数。


编辑:

在互联网上搜索(使用谷歌),我在Jyputer论坛上找到了帖子

Interactive widgets while executing long-running cell - JupyterLab - Jupyter Community Forum

并且有到模块jupyter-ui-poll的链接,该模块显示了类似的示例(while-loop+Button),它使用events来实现这一点。当函数pull()被执行时(在每个循环中),Jupyter可以向窗口小部件发送事件,并且它有时间执行on_click()

import time
from ipywidgets import Button
from jupyter_ui_poll import ui_events

# Set up simple GUI, button with on_click callback
# that sets ui_done=True and changes button text
ui_done = False
def on_click(btn):
    global ui_done
    ui_done = True
    btn.description = '👍'

btn = Button(description='Click Me')
btn.on_click(on_click)
display(btn)

# Wait for user to press the button
with ui_events() as poll:
    while ui_done is False:
        poll(10)          # React to UI events (upto 10 at a time)
        print('.', end='')
        time.sleep(0.1)
print('done')

source code中,我可以看到它使用asyncio来执行此操作。


编辑:

multiprocessing的版本

进程不共享变量,因此需要Queue将信息从一个进程发送到另一个进程。

示例将消息从button发送到function。如果要将消息从function发送到button,则最好使用第二队列。

from IPython.display import display
import ipywidgets as widgets
import time
import multiprocessing

button = widgets.Button(description="STOP!") 
output = widgets.Output()

display(button, output)

queue = multiprocessing.Queue()

def on_button_clicked(event):
    queue.put('stop')
    print("Button pressed")
    
button.on_click(on_button_clicked)

def function(queue):
    
    while True:
        print("While loop")
        time.sleep(1)
        
        if not queue.empty():
            msg = queue.get()
            if msg == 'stop':
                break
            #if msg == 'other text':             
            #    ...other code...
            
    print("Done")
    
multiprocessing.Process(target=function, args=(queue,)).start()

或更类似于上一次

def function(queue):

    break_cicle = True
    
    while break_cicle:
        print("While loop: break_cicle:", break_cicle)
        time.sleep(1)
        
        if (not queue.empty()) and (queue.get() == 'stop'):
            break_cicle = False
        
    print("Done")

编辑:

asyncio的版本

Jupyter已经在运行asynio event loop,我将async function添加到这个循环中。而函数使用await这样的函数,因此asynio event loop有时间运行其他函数-但如果函数只能运行标准(不是异步)函数,则它将无法运行。

from IPython.display import display
import ipywidgets as widgets
import asyncio

button = widgets.Button(description="STOP!") 
output = widgets.Output()

display(button, output)

break_cicle = True

def on_button_clicked(event):
    global break_cicle
    
    break_cicle = False

    print("Button pressed: break_cicle:", break_cicle)
    
button.on_click(on_button_clicked)

async def function():   # it has to be `async`
    while break_cicle:
        print("While loop: break_cicle:", break_cicle)
        await asyncio.sleep(1)   # it needs some `await` functions
    print("Done")
    
loop = asyncio.get_event_loop()    
t = loop.create_task(function())  # assign to variable if you don't want to see `<Task ...>` in output

这篇关于使用Button Jupyter Notebook终止循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆