将数据发送到python

时间:2017-04-18 12:07:23

标签: python matplotlib python-multithreading

我试图通过以下代码编写并向其发送数据(以随机间隔),但我无法弄清楚如何。我将所有数据保存到txt文件并从那里读取信息,它不能很好地工作。是否可以创建一个将数据发送到特定线程的函数(如:SendDataToThread(data,ThreadNumber))?我将如何阅读发送的数据?我已经看到一些使用队列的解决方案,但我无法理解它们。这是我暂时用来绘制我找到的图here的脚本。对不起,如果这个问题看起来很简单,但我以前从未与线程或matplotlib混淆。

import matplotlib.pyplot as plt
from threading import Thread
plt.ion()
class DynamicUpdate():
    #Suppose we know the x range
    min_x = 0
    max_x = 10

    def on_launch(self):
        #Set up plot
        self.figure, self.ax = plt.subplots()
        self.lines, = self.ax.plot([],[], 'o')
        #Autoscale on unknown axis and known lims on the other
        self.ax.set_autoscaley_on(True)
        self.ax.set_xlim(self.min_x, self.max_x)
        #Other stuff
        self.ax.grid()
        ...

    def on_running(self, xdata, ydata):
        #Update data (with the new _and_ the old points)
        self.lines.set_xdata(xdata)
        self.lines.set_ydata(ydata)
        #Need both of these in order to rescale
        self.ax.relim()
        self.ax.autoscale_view()
        #We need to draw *and* flush
        self.figure.canvas.draw()
        self.figure.canvas.flush_events()
    #Example 
    def __call__(self):
        # read/plot data

2 个答案:

答案 0 :(得分:1)

这是一些示例代码,展示了如何处理有关的几个问题。这使用多线程而不是多处理,并显示了一些使用队列,启动/停止工作线程以及使用其他数据更新matplotlib图的示例。

(部分代码来自其他问题的答案,包括this onethis one。)

该代码显示了异步工作程序的可能实现,可以将数据发送到该异步工作程序以供后续处理。 worker使用内部队列来缓冲数据,从队列中读取数据的内部线程(循环)进行一些处理并发送结果以供显示。

还显示了异步绘图仪实现。结果可以从多个工人发送到该绘图仪。 (这也使用内部队列进行缓冲;这样做是为了允许主程序线程本身调用更新绘图的函数,这似乎是matplotlib的要求。)

NB这是在OSX上为Python 2.7编写的。希望其中一些可能有用。

import time
import threading
import Queue
import math
import matplotlib.pyplot as plt

class AsynchronousPlotter:
    """
    Updates a matplotlib data plot asynchronously. 
    Uses an internal queue to buffer results passed for plotting in x, y pairs.
    NB the output_queued_results() function is intended be called periodically
    from the main program thread, to update the plot with any waiting results.
    """

    def output_queued_results(self):
        """
        Plots any waiting results. Should be called from main program thread.
        Items for display are x, y pairs
        """
        while not self.queue.empty():
            item = self.queue.get()
            x, y = item
            self.add_point(x, y)
            self.queue.task_done()

    def queue_result_for_output(self, x, y):
        """
        Queues an x, y pair for display. Called from worker threads, so intended 
        to be thread safe.
        """
        self.lock.acquire(True)
        self.queue.put([x, y]) 
        self.lock.release()

    def redraw(self):
        self.ax.relim()
        self.ax.autoscale_view()
        self.fig.canvas.draw()
        plt.pause(0.001)

    def add_point(self, x, y):
        self.xdata.append(x)
        self.ydata.append(y)
        self.lines.set_xdata(self.xdata)
        self.lines.set_ydata(self.ydata)
        self.redraw()

    def __init__(self):
        self.xdata=[]
        self.ydata=[]
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111)
        self.lines, = self.ax.plot(self.xdata, self.ydata, 'o')
        self.ax.set_autoscalex_on(True)   
        self.ax.set_autoscaley_on(True)   
        plt.ion()
        plt.show()
        self.lock = threading.Lock()
        self.queue = Queue.Queue()

class AsynchronousWorker:
    """
    Processes data asynchronously. 
    Uses an internal queue and internal thread to handle data passed in.
    Does some processing on the data in the internal thread, and then
    sends result to an asynchronous plotter for display
    """

    def queue_data_for_processing(self, raw_data):
        """
        Queues data for processing by the internal thread.
        """
        self.queue.put(raw_data)

    def _worker_loop(self):
        """
        The internal thread loop. Runs until the exit signal is set.
        Processes the supplied raw data into something ready
        for display. 
        """
        while True:
            try:
                # check for any data waiting in the queue
                raw_data = self.queue.get(True, 1)
                # process the raw data, and send for display
                # in this trivial example, change circle radius -> area
                x, y = raw_data
                y = y**2 * math.pi   
                self.ap.queue_result_for_output(x, y)
                self.queue.task_done()
            except Queue.Empty:
                pass
            finally:
                if self.esig.is_set():
                    return

    def hang_up(self):
        self.esig.set()    # set the exit signal...
        self.loop.join()   # ... and wait for thread to exit

    def __init__(self, ident, ap):
        self.ident = ident
        self.ap = ap
        self.esig = threading.Event()
        self.queue = Queue.Queue()
        self.loop = threading.Thread(target=self._worker_loop)
        self.loop.start()

if __name__ == "__main__":     
    ap = AsynchronousPlotter()
    num_workers = 5   # use this many workers

    # create some workers. Give each worker some ID and tell it 
    # where it can find the output plotter
    workers = []
    for worker_number in range (num_workers):
        workers.append(AsynchronousWorker(worker_number, ap)) 

    # supply some data to the workers
    for worker_number in range (num_workers):
        circle_number = worker_number
        circle_radius = worker_number * 4
        workers[worker_number].queue_data_for_processing([circle_number, circle_radius])

    # wait for workers to finish then tell the plotter to plot the results
    # in a longer-running example we would update the plot every few seconds
    time.sleep(2)
    ap.output_queued_results();

    # Wait for user to hit return, and clean up workers
    raw_input("Hit Return...")
    for worker in workers:
        worker.hang_up()

答案 1 :(得分:0)

我改进了代码,我可以在创建它时为它发送一个值,这样做很好,但是通过多处理,我无法弄清楚如何使情节显示。当我在没有多处理的情况下调用绘图时它可以工作,所以它可能是一些我看不到的简单。此外,我正在尝试研究你留下链接的代码,但对我来说,它不是很清楚。我也试图将进程保存到列表中,以便稍后我可以尝试在进程运行时将数据直接发送到进程(我认为这是管道,我这样做但是,我不确定)< / p>

import matplotlib.pyplot as plt
from multiprocessing import Process

plt.ion()
class DynamicUpdate():
    #Suppose we know the x range
    min_x = 0
    max_x = 10
    def __init__(self, x):
        self.number = x
        
    def on_launch(self):
        #Set up plot
        self.figure, self.ax = plt.subplots()
        self.lines, = self.ax.plot([],[], 'o')
        #Autoscale on unknown axis and known lims on the other
        self.ax.set_autoscaley_on(True)
        self.ax.set_xlim(self.min_x, self.max_x)
        #Other stuff
        self.ax.grid()
        ...
        
    def on_running(self, xdata, ydata):
        #Update data (with the new _and_ the old points)
        self.lines.set_xdata(xdata)
        self.lines.set_ydata(ydata)
        #Need both of these in order to rescale
        self.ax.relim()
        self.ax.autoscale_view()
        #We need to draw *and* flush
        self.figure.canvas.draw()
        self.figure.canvas.flush_events()

    #Example
    def __call__(self):
        print(self.number)
        
        import numpy as np
        import time
        self.on_launch()
        xdata = []
        ydata = []
        for x in np.arange(0,10,0.5):
            xdata.append(x)
            ydata.append(np.exp(-x**2)+10*np.exp(-(x-7)**2))
            self.on_running(xdata, ydata)
            time.sleep(1)
        return xdata, ydata

_processes_=[]
for i in range(0,2):
    _processes_.append(Process(target=DynamicUpdate(i)))
    p = Process(target=_processes_[i])
    p.start()
    # tried adding p.join(), but it didn't change anything
    p.join()