sourcetip

matplotlib에서 동적으로 플롯 업데이트

fileupload 2023. 7. 22. 10:20
반응형

matplotlib에서 동적으로 플롯 업데이트

저는 직렬 포트에서 데이터를 수집하고 수집된 데이터를 도착 시간과 비교하여 그래프로 표시하는 파이썬 애플리케이션을 만들고 있습니다.데이터의 도착 시간은 불확실합니다.나는 데이터를 받았을 때 플롯이 업데이트되기를 원합니다.어떻게 하는지 검색해보니 두 가지 방법이 있었습니다.

  1. 플롯을 지우고 모든 점을 사용하여 플롯을 다시 그립니다.
  2. 특정 간격 후에 그림을 변경하여 애니메이션을 만듭니다.

프로그램이 실행되고 데이터를 장시간(예를 들어 하루) 수집하기 때문에 첫 번째 것을 선호하지 않으며, 플롯을 다시 그리는 것은 매우 느릴 것입니다.두 번째 것도 데이터 도착 시간이 불확실하고 데이터를 받았을 때만 플롯이 업데이트되기를 원하기 때문에 바람직하지 않습니다.

데이터를 수신했을 때만 플롯에 포인트를 추가하는 것만으로 플롯을 업데이트할 수 있는 방법이 있습니까?

점을 더 추가하는 것만으로 플롯을 업데이트할 수 있는 방법이 있습니까?

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()

다음은 특정 수의 점이 표시된 후 점을 제거할 수 있는 방법입니다.

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()

제가 이 질문에 답하는 데 늦었다는 것을 알지만, 당신의 문제에 대해서는 "조이스틱" 패키지를 검토해 볼 수 있습니다.직렬 포트의 데이터 스트림을 플롯하기 위해 설계했지만 어떤 스트림에서도 작동합니다.또한 그래프 플로팅 외에도 대화형 텍스트 로깅 또는 이미지 플로팅도 가능합니다.별도의 스레드에서 직접 루프를 수행할 필요 없이 패키지가 처리합니다. 원하는 업데이트 주기만 지정하면 됩니다.또한 플롯 중에 명령을 모니터링하기 위해 터미널을 사용할 수 있습니다.http://www.github.com/ceyzeriat/joystick/ 또는 https://pypi.python.org/pypi/joystick 을 참조하십시오(pip 설치 조이스틱을 사용하여 설치).

아래 코드의 직렬 포트에서 읽은 실제 데이터 포인트로 np.random.random()을 바꾸기만 하면 됩니다.

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()

언급URL : https://stackoverflow.com/questions/10944621/dynamically-updating-plot-in-matplotlib

반응형