2012-06-08 43 views
72

Tôi đang tạo một ứng dụng bằng Python thu thập dữ liệu từ một cổng nối tiếp và vẽ biểu đồ dữ liệu đã thu thập theo thời gian đến. Thời gian đến cho dữ liệu là không chắc chắn. Tôi muốn cốt truyện được cập nhật khi nhận được dữ liệu. Tôi đã tìm kiếm cách thực hiện điều này và tìm thấy hai phương pháp:Tự động cập nhật cốt truyện trong matplotlib

  1. Xóa ô và vẽ lại cốt truyện với tất cả các điểm một lần nữa.
  2. Làm sống động âm mưu bằng cách thay đổi nó sau một khoảng thời gian cụ thể.

Tôi không thích chương trình đầu tiên khi chương trình chạy và thu thập dữ liệu trong một thời gian dài (ví dụ một ngày) và vẽ lại cốt truyện sẽ khá chậm. Điều thứ hai cũng không thích hợp hơn vì thời gian đến của dữ liệu không chắc chắn và tôi muốn cốt truyện chỉ cập nhật khi dữ liệu được nhận.

Có cách nào để tôi có thể cập nhật cốt truyện chỉ bằng cách thêm nhiều điểm hơn vào ô đó khi dữ liệu được nhận không?

+1

có thể trùng lặp của [thời gian thực âm mưu trong khi vòng lặp với matplotlib] (http://stackoverflow.com/questions/11874767/real-time-plotting-in-while-loop-with-matplotlib) –

Trả lời

92

Có cách nào mà tôi có thể cập nhật những âm mưu chỉ bằng cách bổ sung thêm điểm [s] để nó ...

Có một số cách để tạo hiệu ứng động dữ liệu trong matplotlib, tùy thuộc vào phiên bản bạn có. Bạn đã xem các ví dụ matplotlib cookbook chưa? Ngoài ra, hãy xem animation examples hiện đại hơn trong tài liệu matplotlib. Cuối cùng, animation API định nghĩa một hàm FuncAnimation làm động một hàm theo thời gian. Hàm này chỉ có thể là hàm bạn sử dụng để lấy dữ liệu của bạn.

Mỗi phương pháp về cơ bản đặt thuộc tính data của đối tượng đang được vẽ, do đó không yêu cầu xóa màn hình hoặc hình. Các tài sản data chỉ đơn giản là có thể được mở rộng, vì vậy bạn có thể giữ các điểm trước đó và chỉ cần tiếp tục thêm vào dòng của bạn (hoặc hình ảnh hoặc bất cứ điều gì bạn đang vẽ).

Cho rằng bạn nói rằng dữ liệu thời gian xuất hiện của bạn là không chắc chắn đặt cược tốt nhất của bạn có lẽ là chỉ để làm một cái gì đó như:

import matplotlib.pyplot as plt 
import numpy 

hl, = plt.plot([], []) 

def update_line(hl, new_data): 
    hl.set_xdata(numpy.append(hl.get_xdata(), new_data)) 
    hl.set_ydata(numpy.append(hl.get_ydata(), new_data)) 
    plt.draw() 

Sau đó, khi bạn nhận dữ liệu từ cổng nối tiếp chỉ cần gọi update_line.

+0

Cuối cùng! Tôi đã tìm kiếm một câu trả lời cho +1 này :) Làm thế nào để chúng tôi làm cho cốt truyện rescale tự động. ax.set_autoscale_on (True) dường như không hoạt động. –

+11

Tìm thấy câu trả lời: gọi ax.relim() sau đó ax.autoscale_view() sau khi cập nhật dữ liệu nhưng trước khi gọi plt.draw() –

+0

Điều này không hoạt động như mong đợi cho tôi –

19

Để thực hiện điều này mà không cần FuncAnimation (ví dụ bạn muốn thực thi các phần khác của mã trong khi cốt truyện được tạo hoặc bạn muốn cập nhật nhiều ô cùng một lúc), hãy gọi draw một mình (ít nhất là với phụ trợ qt).

Các công trình sau đây cho tôi:

import matplotlib.pyplot as plt 
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): 
     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 

d = DynamicUpdate() 
d() 
+0

Có! Cuối cùng là một giải pháp làm việc với Spyder! Điều tôi đã bỏ lỡ là gcf(). Canvas.flush_events() sau lệnh draw() -. – np8

1

Tôi biết tôi đến trễ để trả lời câu hỏi này, nhưng đối với vấn đề của bạn, bạn có thể nhìn vào gói "điều khiển". Tôi đã thiết kế nó để vẽ một luồng dữ liệu từ cổng nối tiếp, nhưng nó hoạt động cho bất kỳ luồng nào. Nó cũng cho phép ghi lại văn bản tương tác hoặc vẽ hình ảnh (ngoài đồ thị vẽ đồ thị). Không cần thực hiện các vòng lặp của riêng bạn trong một chủ đề riêng biệt, gói sẽ xử lý nó, chỉ cần cung cấp tần suất cập nhật bạn muốn. Thêm vào đó thiết bị đầu cuối vẫn có sẵn để giám sát các lệnh trong khi vẽ đồ thị. Xem http://www.github.com/ceyzeriat/joystick/ hoặc https://pypi.python.org/pypi/joystick (sử dụng pips cài đặt phím điều khiển để cài đặt)

Chỉ cần thay thế np.random.random() bằng điểm dữ liệu thực sự của bạn đọc từ cổng nối tiếp trong mã dưới đây:

import joystick as jk 
import numpy as np 
import time 

class test(jk.Joystick): 
    # initialize the infinite loop decorator 
    _infinite_loop = jk.deco_infinite_loop() 

    def _init(self, *args, **kwargs): 
     """ 
     Function called at initialization, see the doc 
     """ 
     self._t0 = time.time() # initialize time 
     self.xdata = np.array([self._t0]) # time x-axis 
     self.ydata = np.array([0.0]) # fake data y-axis 
     # create a graph frame 
     self.mygraph = self.add_frame(jk.Graph(name="test", size=(500, 500), pos=(50, 50), fmt="go-", xnpts=10000, xnptsmax=10000, xylim=(None, None, 0, 1))) 

    @_infinite_loop(wait_time=0.2) 
    def _generate_data(self): # function looped every 0.2 second to read or produce data 
     """ 
     Loop starting with the simulation start, getting data and 
    pushing it to the graph every 0.2 seconds 
     """ 
     # concatenate data on the time x-axis 
     self.xdata = jk.core.add_datapoint(self.xdata, time.time(), xnptsmax=self.mygraph.xnptsmax) 
     # concatenate data on the fake data y-axis 
     self.ydata = jk.core.add_datapoint(self.ydata, np.random.random(), xnptsmax=self.mygraph.xnptsmax) 
     self.mygraph.set_xydata(t, self.ydata) 

t = test() 
t.start() 
t.stop() 
Các vấn đề liên quan