파이썬으로 GUI 화면과 실시간 그래프 표시

전제



갑자기 GUI를 만들 수 있다고 했다. 버튼등으로 여러가지 제어할 수 있는 리얼타임 그래프 묘화를 하고 싶지만, 성능은 묻지 않는다.
gnuplot 만지지 않았고 C#도 잘 모르지만 Python은 만진 적이 있으므로 matplotlib를 사용해 보겠습니다.

어려운 일이라든지 이상한(?) 라이브러리에의 의존은 하고 싶지 않기 때문에 Python3계의 tkinter를 사용한다.

표시하고 싶은 것은 이하.
  • 꺾은선형 차트 복수
  • 컬러 맵과 해당 컬러 바
  • 제어용 버튼이라든지

  • 사전에 pip install numpy matplotlib 해 둘 필요가 있다.
    (Ubuntu의 경우는 그 전에 sudo apt install python3-pip python3-tk 해 둔다)

    상세



    첫걸음



    버튼과 그래프를 동시에 표시할 필요가 있으므로 まぉぉtぃb. 오 rg 의 검색창에 tkinter 라고 넣어 본다.
    그러면 Embedding in Tk이 맨 위에 있다.

    그리고 리얼타임 그리기로 애니메이션을 할 필요가 있으므로 똑같이 animation 라고 넣어 본다.
    그러면 이번에는 조금 아래쪽에 Animated line plot이 발견된다.

    이번에는 버튼 등을 배치하면서 애니메이션하고 싶기 때문에 상기 2개를 조합할 필요가 있다.

    Animated plot in Tk



    Embedding in TkAnimated line plot 을 합체하여 조금 정리했다.
    #!/usr/bin/env python3
    
    
    # https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
    # https://matplotlib.org/gallery/animation/simple_anim.html
    
    
    import tkinter
    
    from matplotlib.backends.backend_tkagg import (
        FigureCanvasTkAgg, NavigationToolbar2Tk)
    from matplotlib.figure import Figure
    import matplotlib.animation as animation
    
    import numpy as np
    
    
    def _quit():
        root.quit()     # stops mainloop
        root.destroy()  # this is necessary on Windows to prevent
                        # Fatal Python Error: PyEval_RestoreThread: NULL tstate
    
    
    def init():  # only required for blitting to give a clean slate.
        line.set_ydata(np.sin(x))
        return line,
    
    
    def animate(i):
        line.set_ydata(np.sin(x + i))  # update the data.
        return line,
    
    
    root = tkinter.Tk()
    root.wm_title("Embedding in Tk anim")
    
    fig = Figure()
    # FuncAnimationより前に呼ぶ必要がある
    canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
    
    x = np.arange(0, 3, 0.01)  # x軸(固定の値)
    l = np.arange(0, 8, 0.01)  # 表示期間(FuncAnimationで指定する関数の引数になる)
    plt = fig.add_subplot(111)
    plt.set_ylim([-1.1, 1.1])
    line, = plt.plot(x, np.sin(x))
    
    ani = animation.FuncAnimation(fig, animate, l,
        init_func=init, interval=10, blit=True,
        )
    
    toolbar = NavigationToolbar2Tk(canvas, root)
    canvas.get_tk_widget().pack()
    
    button = tkinter.Button(master=root, text="Quit", command=_quit)
    button.pack()
    
    tkinter.mainloop()
    

    버튼 등은 보통 tkinter로 배치할 수 있다.

    외형





    주의점


  • animation.FuncAnimation() 로 반환되는 객체(위의 코드에서는 ani )의 참조가 없는(?)와 그래프가 갱신되지 않는 경우가 있다.
    클래스로 했을 경우는 ,.
    (위의 코드에서 self.ani가 없으면 안될 수 있습니다.)
  • ani = ... 라든지 set_ydata() 에서는, 데이터 이외의 표시는 갱신되지 않는다.
    Y축 범위를 자동 추종하고 싶은 경우라든가는, 자전으로 set_data() 할 필요가 있다.
  • set_ylim() 그러면 그래프가 갱신되지 않는 (축 라벨만의 갱신이라든지가 반영되지 않는) 일이 있다.
    버튼으로 X축 표시 모드 바꾸고 싶은데 변하지 않을 때는 blit=True 로 해 보면 좋을지도 모른다.

  • 응용(?) 예



    Python에서 I2C 센서(CCS811/BME280)를 읽고 여러가지 표시해 보았다 그리고 이번 성과를 사용했다.
    matplotlib에서의 표시는 이 코드 (example.py) 센서로 값을 취득하는 관계로 클래스를 사용해서 즐겁게 했다.

    좋은 웹페이지 즐겨찾기