본문 바로가기
Python

Python PyQt5 프로젝트 - Excel / CSV 파일 데이터 그래프 그리기 (3)

by 아짱이아빠 2022. 10. 14. 16:35
반응형

마지막 3부에서 Excel 파일과 CSV 파일 데이터를 그래프로 그리는 파이썬 프로그램 중 각 버튼과 창에 기능을 설정하는 부분과 실행 파일로 만드는 방법 그리고 샘플 데이터를 통한 결과를 확인해 보겠다. 

이 프로그램의 전체적인 구조와 GUI 설정에 대해서는 아래의 링크에 있으니 참고하면 되겠다.

 

 

Python PyQt5 프로젝트 - Excel / CSV 파일 데이터 그래프 그리기 (2)

2부에서는 본격적으로 Excel 파일과 CSV 파일 데이터를 그래프로 그리는 파이썬 코드에 대해 정리해보겠다. 프로그램 비전공자로서 프로그램에 빨리 친숙해지려면 무언가를 만들어보는 것이 가장

superhky.tistory.com

 

[버튼 기능 정의]

(1) 파일 형식 선택 (filopenActivated)

2부에서 각 버튼 및 창을 만들었고 전체적인 레이아웃 구성을 정의하였다.

2부에서 만든 버튼 및 창에 기능을 정의해야 하는데 먼저 다음의 코드는 Excel 또는 CSV 파일을 오픈하는 버튼에 대한 기능을 정의한다.

def fileopenActivated(self, text):
      if text == 'Excel File':
          self.listwidget_01.clear()
          self.data = pd.DataFrame()
          fname01 = QFileDialog.getOpenFileName(self)
        
          try:
            self.data=pd.read_excel(fname01[0], index_col=0)
            i = 1      
            for i in range(len(self.data.columns)):
              temp_Item = QListWidgetItem(self.data.columns[i])
              self.listwidget_01.addItem(temp_Item)

          except ValueError:
            QMessageBox.warning(self, '형식이 일치하지 않습니다.', '형식이 일치하는 파일을 불러오시오')     

          except FileNotFoundError:
            QMessageBox.warning(self, '파일이 없습니다.', '형식에 맞는 파일을 선택하시오')

      if text == 'CSV File':
          self.listwidget_01.clear()
          self.data = []
          fname02 = QFileDialog.getOpenFileName(self)         

          try:
            self.data=pd.read_csv(fname02[0], index_col=0)
            i = 1      
            for i in range(len(self.data.columns)):
              temp_Item = QListWidgetItem(self.data.columns[i])
              self.listwidget_01.addItem(temp_Item)

          except UnicodeDecodeError:
            QMessageBox.warning(self, '형식이 일치하지 않습니다', '형식이 일치하는 파일을 불러오시오')      

          except FileNotFoundError:
            QMessageBox.warning(self, '파일이 없습니다.', '형식에 맞는 파일을 선택하시오')

 

2부에서 QComboBox에는 ‘Excel File’과 ‘CSV File’ 두 개의 text를 설정했었다.

여기서는 if 문을 통해 이 두 개의 text 중 어느 하나가 선택되면 동작하도록 되어 있으며 둘은 동일한 구조의 코드로 구성된다.

만약, Excel 파일을 선택하게 되면 먼저 .clear() 메서드를 통해 혹시 이전에 불러온 column 명들이 'self.listwidget_01' 창에 남아 있다면 이를 지우도록 한다.

그리고 선택된 Excel 파일의 내용을 담을 빈 데이터 프레임을 하나 정의하며 QFileDialog를 통해 파일 선택 창을 열고 .getOpenFileName 메서드를 사용해서 파일을 선택할 수 있게 한다.

 

Excel 파일이 선택되면 안의 데이터를 앞에서 만든 빈 데이터 프레임인 ‘self.data’에 저장하는데 이때 ‘index_col=0’을 통해 Excel 데이터의 첫 column을 인덱스로 지정한다.

이는 그래프로 그리고자 하는 Excel이나 CSV의 데이터가 첫 column에 날짜 또는 시간 또는 그 외에 특정 순번 등을 x 축에 그대로 표현하고자 함이다.

즉, 이 프로그램은 데이터의 첫 column이 x 축에 표현될 정보로 정의되어 있어야만 하며 만약 그렇지 않고 첫 column부터 데이터들만 있다면 결과가 이상해질 수 있음을 알아둘 필요가 있다.

 

self.data에 저장된 Excel 파일의 내용은 for 문을 통해 하나씩 column 명을 읽어서 ‘temp_Item’ 변수에 저장하고 ‘.addItem()’ 메서드를 통해 ‘self.listwidget_01’에 표시한다.

 

그다음은 경고 메시지 창을 띄우는 기능을 정의한다.

Excel File을 오픈하기 위해 눌렀지만 실제 파일을 선택하는 다이얼로그에서 CSV 파일을 누르거나(ValueError) 또는 아무 파일도 선택하지 않으면(FileNotFoundError) 거기에 맞춰 경고 메시지를 띄운다.

이 경고 메시지를 띄우기 위해 try 문에 정상 기능을 넣고 예외사항이 생겼을 때를 감지하기 위해 except 문을 사용한다. 

 

CSV File을 선택했을 때의 기능과 정의는 위와 동일하므로 설명은 생략하겠다.

 

 

(2) 그래프 스타일 결정 (onActivated)

다음은 그래프 스타일을 선택했을 때의 기능을 정의한다.

def onActivated(self, value):
      plt.style.use(value)
      self.graphplot()

 

위의 코드처럼 간단히 ‘plt.style.use(value)’ 명령을 통해 선택할 수 있으며 value에 해당하는 그래프 스타일들은 2부에서 정의하였고 그중에서 하나가 선택된다.

‘self.graphplot()’은 이 프로그램에서 핵심이 되는 그래프를 그리는 기능을 정의하고 있으며 자세한 코드는 아래에서 알아보겠다.

이 그래프 스타일 기능에 ‘self.graphplot()’가 있다는 의미는 그래프 스타일을 결정하면 그때 바뀐 스타일에 맞게 그래프를 다시 그리기 위함이다.

 

(3) 그리고자 하는 column을 선택 (doubleclicked_listwidget)

다음 기능은 <Column List> 창에 표시되어 있는 Excel 또는 CSV 파일의 column 명 중에서 그래프로 그리고자 하는 colunm 명을 선택하는 기능이다.

기능 명에도 있듯이 마우스로 더블클릭을 통해 기능이 동작한다.

def doubleclicked_listwidget(self):
    list_item = self.listwidget_01.selectedItems()

    for item in list_item:
      self.listwidget_02.addItem(item.text())

 

정의 안에 있는 첫 번째 코드는 마우스 더블클릭으로 특정 column 명을 선택하면 이를 ‘list_item’ 변수에 저장한다.

이후 for 문을 통해 이 변수에서 저장된 column명 text를 <Graph List> 창인 ‘self.listwidget_02’에 표시한다.  

 

 

(4) 선형/막대형 그래프 선택 (graph_selec)

다음은 이 프로그램의 또 다른 기능인 그래프 종류를 선택하는 기능을 정의한다.

간단히 선형 그래프와 막대형 그래프 둘 중에 하나를 선택할 수 있다.

  def graph_selec(self):
      if self.line_graph_btn.isChecked():
          self.graphplot()

      if self.hist_graph_btn.isChecked():
          self.graphplot()

 

코드는 간단히 어떤 그래프 종류가 선택되더라도 그래프를 그리는 ‘self.graphplot()’ 기능으로 연결된다.

여기서 ‘self.graphplot()’ 기능 정의에 두 그래프 기능이 각각 정의되어 있을 것이라는 것을 알 수 있다.

 

 

(5) 그래프 그리기 (graphplot)

다음이 그래프를 그리는 기능을 정의하고 있으며 이 프로그램에서 핵심이 되는 기능이다. 

  def graphplot(self):
    num = 0
    num = self.listwidget_02.count()      
    sel_culm = []                         
    new_data = pd.DataFrame()            
    selection = []

    if num == 0:
      plt.close()

    for i in range(0,num):
      selection = self.listwidget_02.item(i)
      sel_culm = selection.text()          
      if sel_culm in self.data.columns:
          new_data[sel_culm] = self.data[sel_culm]

          if self.line_graph_btn.isChecked():
              plt.close()
              plt.plot(new_data, label=new_data.columns)
              plt.xticks(rotation=90)
              plt.margins(x=0,y=0)
              legend = plt.legend()    
              legend.set_draggable(True) 
              plt.grid(True)
              plt.show()      

          if self.hist_graph_btn.isChecked():
              plt.close()
              plt.hist(new_data, label=new_data.columns)
              plt.xticks(rotation=90)
              plt.margins(x=0,y=0)
              legend = plt.legend()     
              legend.set_draggable(True)    
              plt.grid(True)
              plt.show()      

      else:
          QMessageBox.warning(self, '형식이 일치하지 않습니다,', '다른 형식의 파일에서 불러온 column을 지우시오')

  

그래프를 그리는 기능은 실행에 필요한 변수들을 정의하고 그래프를 그리고자 선택된 column 명을 확인하고 선형 그래프 또는 막대형 그래프 중 선택된 그래프 종류에 맞춰 그래프를 그리는 구조로 구성되어 있다.

 

변수 ‘num’에는 <Graph List>에 들어있는 column 개수를 세어 저장한다.

만약 ‘num’이 0이면 즉, 그래프를 그리고자 하는 선택된 column이 하나도 없다면 그래프를 지운다.

‘num’에 한 개라도 저장된다면 for 문을 통해 그 수만큼 column 명을 ‘sel_culm’ 변수에 저장하고 이 column명과 일치하는 데이터들만 모아 새로운 데이터 프레임인 ‘new_data’에 저장한다.

 

다음은 선택된 그래프 종류에 따라 이 ‘new_data’에 있는 내용을 그린다.

그래프는 legend가 표시되고 이 legend는 ‘.set_draggable(True)’ 메서드를 이용하여 마우스로 결과 그래프상에서 legend를 움직일 수 있다.

 

마지막은 다른 형식의 파일에서 선택된 column 명이 <Graph List> 창에 섞여 있을 수 있기 때문에 이러한 경우에 경고 메시지를 띄우는 기능이다.

예를 들면, Excel 파일을 열어 column을 선택하여 그래프를 그렸고 이후 연달아서 CSV 파일을 열게 되면 <Column List>에는 앞의 (1) 파일 형식 선택 (filopenActivated) 기능에서 있었던 .clear() 메서드를 통해 이전 Excel 파일에 있던 column은 지워지고 CSV 파일의 column이 표시된다.

하지만 <Graph List>에는 Excel 파일에서 그래프로 그리려고 선택된 column 명이 남아 있으며 이 경우에 결과 그래프에 영향을 주기 때문에 다른 형식의 파일에서 불러온 column을 지우라는 경고 메시지를 띄운다.

Column을 지우는 기능은 다음에서 설명하겠다.

 

반응형

 

(6) Column 지우기 (grapherase)

다음은 그래프로 그리려고 선택한 column 중에 다시 지우고 싶은 column이 있을 때 이를 선택하여 지우는 기능을 정의한다.

  def grapherase(self):
      erase_item = self.listwidget_02.currentRow()
      self.listwidget_02.takeItem(erase_item)
      self.graphplot()

 

코드는 <Graph List> 창인 ‘self_listwidget_02’에서 지우고자 하는 column을 선택하면 이는 변수 ‘erase_item’에 저장되고 ‘.takeItem()’ 메서드를 통해 해당 column을 삭제한다.

이후 ‘self.graphplot()’ 기능을 다시 호출하여 그래프를 다시 그린다.

 

 

(7) 프로그램 창을 화면의 중심에 배치

다음의 코드는 프로그램 GUI 창과 결과 그래프를 화면의 중심에 띄우는 기능을 정의한다.

  def center(self):        
      qr = self.frameGeometry()
      cp = QDesktopWidget().availableGeometry().center()
      qr.moveCenter(cp)
      self.move(qr.topLeft())

 

끝으로 다음의 코드는 프로그램을 빠져나올 수 있도록 한다. 

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

 

[실행파일 생성]

이렇게 만든 GUI 프로그램은 실행파일로 만듦으로써 파이썬이 깔려있지 않은 컴퓨터에서도 실행할 수 있다.

PyQt5로 만든 프로그램은 PyInstaller를 이용하여 쉽게 실행파일을 만들 수 있다.

 

컴퓨터의 명령 프롬프트를 열고 파이썬 코드 파일이 있는 폴더에 들어간다.

그리고 다음의 명령어를 입력하면 실행파일을 만들 수 있다.

 

pyinstaller -w -F 파이썬 코드 이름.py

 

일정 시간 후에 “~completed successfully”란 메시지를 확인한 후 파이썬 코드가 있는 폴더에 가면 ‘dist’ 란 이름의 폴더가 생성되어 있을 것이며 이 폴더 안에 실행파일 하나가 만들어져 있을 것이다.   

만약 PyInstaller가 깔려 있지 않다면 pip install pyinstaller 명령을 통해 설치할 수 있다.

 

 

[프로그램 결과 데모]

아래는 프로그램을 실행한 화면이다. 

앞에서 설명한 바와 같이 실행하면 화면에 중심에 창이 열린다.

프로그램 실행 화면
(프로그램 실행 화면)

 

 

다음은 CSV 파일로 만든 가상화폐의 데이터를 불러와서 open, high, low, close 가격 정보를 다양한 그래프 스타일과 막대형 그래프로 그려본 것이다. 

프로그램 실행 결과
(프로그램 실행 결과)



[결 론]

여기까지 Excel 파일 또는 CSV 파일을 불러와서 내부의 각 column에 있는 데이트를 다양한 그래프 스타일과 종류로 그리는 파이썬 PyQt5 코드에 대해 알아봤다.

이 프로그램을 만들어 봄으로써 간단히나마 파이썬 GUI 프로그램을 공부할 수 있었다.

PyQt5의 버튼이나 창을 만들고 레이아웃을 구성하며, 각 버튼과 창에 여러 가지 기능을 정의하는 방법, 그리고 기타 툴팁이나 아이콘 삽입, 경고 메시지를 띄우는 방법을 습득할 수 있었다.

 

앞으로 좀 더 기능이 복잡하면서 재미있는 프로그램을 만들어 볼 계획이다.

  

 

반응형

댓글