matplotlib에서 동적으로 플롯 업데이트
직렬 포트에서 데이터를 수집하고 도착 시간에 대해 수집 된 데이터의 그래프를 그리는 Python으로 응용 프로그램을 만들고 있습니다. 데이터 도착 시간은 불확실합니다. 데이터가 수신되면 플롯을 업데이트하고 싶습니다. 이 작업을 수행하는 방법을 검색하고 두 가지 방법을 찾았습니다.
- 플롯을 지우고 모든 포인트로 플롯을 다시 그립니다.
- 특정 간격 후에 플롯을 변경하여 애니메이션화합니다.
프로그램이 장시간 (예 : 하루) 데이터를 실행하고 수집하므로 첫 번째 것을 선호하지 않으며 플롯을 다시 그리는 속도가 매우 느립니다. 두 번째 것은 데이터 도착 시간이 불확실하고 데이터가 수신 될 때만 플롯이 업데이트되기를 원하기 때문에 바람직하지 않습니다.
데이터를받을 때만 더 많은 포인트를 추가하여 플롯을 업데이트 할 수있는 방법이 있습니까?
더 많은 포인트를 추가하여 플롯을 업데이트 할 수있는 방법이 있습니까?
사용중인 버전에 따라 matplotlib에서 데이터를 애니메이션하는 방법에는 여러 가지가 있습니다. matplotlib 요리 책 예제를 보셨습니까 ? 또한 matplotlib 문서에서 보다 현대적인 애니메이션 예제 를 확인하십시오 . 마지막으로 애니메이션 API 는 시간에 따라 함수를 애니메이션하는 함수 FuncAnimation 을 정의합니다 . 이 함수는 데이터를 수집하는 데 사용하는 함수일 수 있습니다.
각 방법은 기본적으로 data
그려지는 객체 의 속성을 설정 하므로 화면이나 그림을 지울 필요가 없습니다. data
이전 포인트를 유지하고 당신의 라인 (또는 이미지 또는 당신이 무엇을 그리는)에 계속 추가 할 수 있도록 속성을 간단하게 확장 할 수 있습니다.
데이터 도착 시간이 확실하지 않다고한다면 다음과 같이하는 것이 가장 좋습니다.
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()
그런 다음 직렬 포트에서 데이터를 수신하면 update_line
.
FuncAnimation없이이 작업을 수행하려면 (예 : 플롯이 생성되는 동안 코드의 다른 부분을 실행하거나 동시에 여러 플롯을 업데이트하려는 경우) draw
단독으로 호출 하면 플롯이 생성되지 않습니다 (적어도 qt 백엔드).
다음은 나를 위해 작동합니다.
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()
I know I'm late to answer this question, but for your issue you could look into the "joystick" package. I designed it for plotting a stream of data from the serial port, but it works for any stream. It also allows for interactive text logging or image plotting (in addition to graph plotting). No need to do your own loops in a separate thread, the package takes care of it, just give the update frequency you wish. Plus the terminal remains available for monitoring commands while plotting. See http://www.github.com/ceyzeriat/joystick/ or https://pypi.python.org/pypi/joystick (use pip install joystick to install)
Just replace np.random.random() by your real data point read from the serial port in the code below:
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()
Here is a way which allows to remove points after a certain number of points plotted:
import matplotlib.pyplot as plt
# generate axes object
ax = plt.axes()
# set limits
plt.xlim(0,10)
plt.ylim(0,10)
for i in range(10):
# add something to axes
ax.scatter([i], [i])
ax.plot([i], [i+1], 'rx')
# draw the plot
plt.draw()
plt.pause(0.01) #is necessary for the plot to update for some reason
# start removing points if you don't want all shown
if i>2:
ax.lines[0].remove()
ax.collections[0].remove()
참고URL : https://stackoverflow.com/questions/10944621/dynamically-updating-plot-in-matplotlib
'IT story' 카테고리의 다른 글
INT, INTEGER, SMALLINT 및 TINYINT와 같은 관련 SQLite 데이터 유형의 차이점은 무엇입니까? (0) | 2020.08.20 |
---|---|
단일 파일의 병합 다시 실행 (0) | 2020.08.20 |
C # 용 파서 (0) | 2020.08.20 |
Maven : 수명주기 대 단계 대 플러그인 대 목표 (0) | 2020.08.20 |
Perl CGI 스크립트의 문제를 어떻게 해결할 수 있습니까? (0) | 2020.08.20 |