사냥꾼의 IT 노트

[PyQt5]npy 파일을 그래프로 출력하는 프로그램 본문

python

[PyQt5]npy 파일을 그래프로 출력하는 프로그램

가면 쓴 사냥꾼 2023. 4. 27. 16:14

※본 연구는 Windows 환경에서 진행됩니다.


(PyQt5에 대해서는 다음 링크 참조)

https://it-the-hunter.tistory.com/66

 

PyQt5에 대해 알아보자 (개념/설치)

1. 개념 PyQt5는 Qt5 어플리케이션 프레임워크에 대한 파이썬 버전이다. 여기서 Qt는, C++ 라이브러리 개발툴로 그래프 같은 기하학적인 부분을 다룬다. PyQt5는 이런 Qt에 대한 다양한 기능을 파이썬

it-the-hunter.tistory.com


개요

npy 파일은 numpy 라이브러리로 생성된 다차원 배열 데이터를 저장하는 바이너리 파일이다. numpy 배열은 파이썬에서 고성능 수치 계산을 위해 사용된다. 

npy 파일은 다차원 배열 데이터를 포함하기 때문에 배열의 크기나 데이터 타입을 확인해야 그 종류를 대략적으로 알 수 있다.


1. npy 배열 확인하기

다음과 같은 코드로 npy 파일의 배열을 확인할 수 있다.

import numpy as np

arr = np.load('test.npy')
print(arr.ndim)

해당 npy 파일이 몇 차원 배열인지 출력된다.

자 이제 몇차원인지 알았다. 아마 대부분의 npy 파일은 2차원 배열일 것이다. 따라서 이 npy 파일을 그래프로 출력하기 위한 프로그램을 작성해보자.


2. 라이브러리 import

import sys
import os
from PyQt5.QtWidgets import *
import pyqtgraph as pg
import numpy as np
import time
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, Qt, QThread, QTimer

그래프를 그리기 위해 PyQt5와 가장 유명한 라이브러리 matplotlib을 이용한다.


3. 클래스 생성

코드의 가독성과 함수를 한번에 실행하기 위해 다음 클래스를 생성한다.

class MyApp(QWidget):

4. 프로그램 초기 화면 함수 생성

def __init__(self):
        super().__init__()

        self.respiration_data1 = None

        self.right_num = 0
        self.left_num = 0

        # 파일 라벨
        self.lbl1 = QLabel('npy file:', self)

        # 파일명
        self.le1 = QLineEdit(self)

        # 파일 열기 버튼
        self.file_open_btn1 = QPushButton('열기', self)

        # plot 부분
        self.fig1 = plt.Figure()
        self.canvas1 = FigureCanvas(self.fig1)
        
        self.initUI()

첫 실행 시 표기되는 부분을 위한 함수다. 

  • # 파일 라벨 : 파일을 선택할 때, 어떤 파일을 선택할 지 실행자에게 알려주기 위한 부분이다. 필자는 npy 데이퍼를 선택할 것이기 때문에 임의로 'npy file'라고 지정했다.
  • # 파일명 : 인수 self 로 파일명을 받아온다.
  • # 파일 열기 버튼 : 단순이 파일을 열기 위한 버튼의 이름을 지정해준다.
  • # plot 부분 : 이는 npy 데이터를 그리기 위한 부분이다. 라이브러리 matplotlib의 Fiqurecanvas를 이용한다.

5. 버튼 및 윈도우 그리기 함수

    def initUI(self):

        # 파일 열기
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.lbl1)
        hbox1.addWidget(self.le1)
        hbox1.addWidget(self.file_open_btn1)

        # 좌측 화면
        left_layout = QVBoxLayout()
        left_layout.addLayout(hbox1)
        left_layout.addWidget(self.canvas1)

        # 좌우 통합
        lr_layout = QHBoxLayout()
        lr_layout.addLayout(left_layout)

        # 전체 화면
        full = QVBoxLayout()
        full.addLayout(lr_layout)

        self.setLayout(full)

        # 파일 열기 버튼
        self.file_open_btn1.clicked.connect(self.btn_file_load_1)

        self.setWindowTitle('respiration data print tool')
        self.setGeometry(300, 200, 900, 600)
        self.show()

본격적으로 프로그램이 수행하는 핵심 부분이다.

  • 먼저 파일 열기 버튼을 캔버스에 배치하기 위해 hbox1을 생성한다. 특히 QHBoxLayout는 행 방향으로 위젯을 배치하기 위함이다. 즉, 끝 방향에 버튼을 배치한다.
  • # 좌측 화면&# 좌우 통합&# 전체 화면 : 윈도우 크기가 바뀔 때를 대비한 코드이다. 특히 QVBoxLayout은 위젯을 수직 방향으로 배치하기 위함이다.
  • 파일 열기 버튼 : 본격적으로 파일을 선택해 열기 위한 코드이다. 밑에서 생성할 함수 'btn.file_load_1'을 반환한다.
  • setWindowTitle&selfGrometry : 윈도우의 타이틀과 초기 실행 시 화면 크기를 정하는 부분이다. 

6. 파일 불러오기 함수

    def btn_file_load_1(self):
        self.fig1.clf()
        self.left_num = 0
        fname = QFileDialog.getOpenFileName(self, '', '', 'respiration file(*.npy);; All File(*)')

        if fname[0]:
            self.le1.setText(fname[0].split('/')[-1])
            self.respiration_data1 = np.load(fname[0])
            ax = self.fig1.add_subplot(111)
            ax.set_ylim([-1, 1])
            ax.plot(self.respiration_data1[-1200:])
            self.canvas1.draw()

버튼을 눌러 파일을 열고, 캔버스에 그리기 위한 함수이다.

  • QFileDialog.getOpenFileName(, , , ...) : 파일 열기를 위한 대화상자를 생성한다. 첫번째 인자는 MyApp 클래스의 인스턴스에 속하도록 설정하며, 두번째 인자는 파일 대화상자의 타이틀을 지정한다.
    • (*.npy) : 세번째 인자로 파일의  필터를 지정한다. 본 프로그램에서는 npy 파일을 불러오기 때문에 *.npy라고 작성했다.
  • if ~~~ : 선택된 파일을 numpy 라이브러리로 읽어오고 캔버스에 그리는 역할을 한다.
    • np.load(fname[0]) : 선택된 npy 파일을 읽어온다.
    • ax = self.fig1.add_subplot(111) : matplotlib을 이용해 서브플롯을 생성한다. 이는 여러 개의 작은 그래프를 그려 가시성을 높이기 위함이다.
    • ax.set_ylim([-1, 1]) : 그래프를 그릴 때 y축 범위를 -1~1로 설정한다.
    • ax.plot(self.respiration_data1[-1200:]) : x축 범위는 1200으로 지정한다. 
    • self.canvas1.draw() : 캔버스에 전체적인 그래프를 그린다.

7. 최종 실행 코드

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

PyQt5를 사용한 GUI 어플리케이션을 실행하기 위한 코드다. 코드의 로직은 다음과 같다.

  • PyQt5의 QApplication 객체를 생성하고, MyApp 클래스의 인스턴스를 생성해 실행한다.
  • sys.exit(app.exec_()) : 프로그램이 종료될 때까지 실행을 유지한다.

실행 결과

초기 실행 화면
전체화면
npy 파일을 불러온 모습