πŸ’‘ Data Analysis/πŸ“‚ Project - Analysis of KakaoTalk (end)

[QT][Python] ν•¨μˆ˜μ™€ QT μ—°κ²°ν•˜κΈ° (4)

Sun A 2024. 8. 12. 11:18
#1. νŒŒμΌ μ°Ύμ•„보기 λ²„νŠΌ - fl_btn
#2. νŒŒμΌ κ²½λ‘œ λ‚˜νƒ€λ‚˜λŠ” λ²„νŠΌ - fl_lbl
#3. λΆ„석 κΈ°λŠ₯ μ§€μ • λ“œλ‘­λ‹€μš΄ λ²„νŠΌ - fun_cb
        # μ‚¬μš©μžλ³„ λŒ€ν™” λΉˆλ„
        # μ‚¬μš©μžλ³„ μ΄λͺ¨ν‹°μ½˜ μ‚¬μš© λΉˆλ„
        # μ‚¬μš©μžλ³„ ν™œλ™ μ‹œκ°„λŒ€ 
        # μ‚¬μš©μžλ³„ ν‰κ·  λ‹΅λ³€ μ‹œκ°„
#4. μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„ λΆ„석 μ°Έμ—¬μž μ„ νƒ ν…μŠ€νŠΈ μž…λ ₯ λ°•μŠ€ - filter_te
#5. λΆ„석 κ²°κ³Ό μ΄λ―Έμ§€ λ‹€μš΄λ‘œλ“œ λ²„νŠΌ - down_btn
#6. λΆ„석(Start) Run λ²„νŠΌ - st_btn
#7. μ΄ˆκΈ°ν™”(Reset) Run λ²„νŠΌ - rst_btn

#8. κ²°κ³Ό ν™”λ©΄ - ptr_lbl

 

이제 λ§ˆμ§€λ§‰μœΌλ‘œ 남은 λ²„νŠΌμ€ 4번과 5λ²ˆμ΄λ‹€.

μ•„λ¬΄λž˜λ„ ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜κ³  이미지λ₯Ό λ‹€μš΄λ‘œλ“œ ν•˜λŠ” λ²„νŠΌμ΄ κ°€μž₯ μ–΄λ ΅λ‹€κ³  느껴쑌기 λ•Œλ¬Έμ— λ§ˆμ§€λ§‰μœΌλ‘œ μž‘μ—…μ„ ν–ˆλ˜ 것 κ°™λ‹€. (ν•˜μ§€λ§Œ κ°€μž₯ μ–΄λ €μš΄ μž‘μ—…μ€ μ•„λ‹ˆμ—ˆλ˜ 것 κ°™λ‹€.)


#4. μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„ λΆ„석 μ°Έμ—¬μž μ„ νƒ ν…μŠ€νŠΈ μž…λ ₯ λ°•μŠ€ - filter_te

ν…μŠ€νŠΈ λ°•μŠ€μ— 이름을 μž…λ ₯ν•˜μ—¬ μ°Έμ—¬μžλ³„λ‘œ μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„ μ‹œκ°„μ— λŒ€ν•œ 파이차트λ₯Ό 좜λ ₯ν•˜λŠ” 것은 ν•˜λ‚˜μ˜ κΈ°λŠ₯μ—λ§Œ ν•΄λ‹Ήλ˜λŠ” 것이닀.

κ·Έλž˜μ„œ λ‹€μ–‘ν•œ 방법을 κ³ λ―Όν•˜λ‹€κ°€ κ·Έλƒ₯ λ‹€λ₯Έ κΈ°λŠ₯듀을 μ„ νƒν•˜κ³  뢄석 λ²„νŠΌμ„ λˆ„λ₯Ό λ•Œ μ°Έμ—¬μž 필터링에 μž…λ ₯값이 μžˆλ“  μ—†λ“  상관없이 μ›λž˜ 값이 좜λ ₯λ˜λ„λ‘ ν•œλ‹€.

ν•˜μ§€λ§Œ 'μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„' κΈ°λŠ₯을 μ„ νƒν•˜κ³  이름값을 μ •ν™•ν•˜κ²Œ μž…λ ₯ν•˜λ©΄ μ œλŒ€λ‘œλœ 필터링이 λ˜λ„λ‘ μ½”λ“œλ₯Ό μ§œλŠ” κ²ƒμœΌλ‘œ κ³„νšν–ˆλ‹€.

λŒ€μ‹  이름이 ν‹€λ¦¬κ±°λ‚˜ 빈칸으둜 [뢄석] λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ 전체 νŒŒμ΄κ°’μ΄ 좜λ ₯λ˜λ„λ‘ μ„€μ •ν–ˆλ‹€.

기쑴의 ν•¨μˆ˜λ₯Ό μ •μ˜ν•œ pyνŒŒμΌμ—μ„œλ„ 전체 좜λ ₯κ³Ό κ°œλ³„ 좜λ ₯ 값이 λͺ¨λ‘ λ‚˜μ˜€λ„λ‘ μ„€μ •λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό κ·ΈλŒ€λ‘œ ν™œμš©ν•˜λ©΄ λœλ‹€.

 

μš°μ„  기쑴에 μž‘μ„±ν–ˆλ˜ "μ‚¬μš©μžλ³„ 각 μ‹œκ°„λŒ€ ν™œλ™ λΉˆλ„ 뢄석"의 ν•¨μˆ˜μ—μ„œ  name 필터링 λ‹€μŒμ— 파이 차트λ₯Ό 좜λ ₯ν•˜λŠ” 값이 쑰금 λ³€κ²½λ˜μ—ˆλ‹€.

    # 파이 차트 생성
    if not pivot_table.empty:
        fig, ax = plt.subplots()
        
        pivot_table.iloc[0].plot(kind='pie', ax=ax, autopct='%1.1f%%', startangle=90, legend=False)
        ax.set_title(f"{names[0]}의 μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„")
        ax.set_ylabel('')
        plt.tight_layout()
        
    else:
        pivot_table = activity_by_time.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)

        fig, axes = plt.subplots(nrows=1, ncols=len(pivot_table), figsize=(15, 5))
    
        for i, (names, data) in enumerate(pivot_table.iterrows()):
            data.plot(kind='pie', ax=axes[i], autopct='%1.1f%%', startangle=90, legend=False)
            axes[i].set_title(names)
            axes[i].set_ylabel('')
        plt.tight_layout()

μ›λž˜λŠ” if not κ°’κ³Ό else κ°’μ˜ μˆœμ„œκ°€ λ‹¬λžλ‹€.

pivot_table 값은 μ•„λž˜μ™€ 같은데 

pivot_table = user_data.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)

μœ„μ— μž…λ ₯된 names 값이 인덱슀둜 λ“€μ–΄κ°€μ„œ 값을 좜λ ₯ν•˜λŠ” 것을 pivot_table에 넣은 것이닀.

λ§Œμ•½ pivot_table 값이 λΉ„μ–΄μžˆμ§€ μ•Šλ‹€λ©΄ Name 값이 μž…λ ₯된 것이기 λ•Œλ¬Έμ— κ°œλ³„λ‘œ 좜λ ₯λ˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν–ˆμ§€λ§Œ λΉ„μ–΄μžˆκ±°λ‚˜ μ œλŒ€λ‘œ μž…λ ₯λ˜μ§€ μ•Šμ•˜λ‹€λ©΄ λ‹€μ‹œ pivot_table을 μ •μ˜ν•˜μ—¬ λ°˜λ³΅λ¬Έμ— μ˜ν•΄ λͺ¨λ“  값이 좜λ ₯λ˜λ„λ‘ μž‘μ„±ν•˜μ˜€λ‹€.

 

이 ν•¨μˆ˜λ₯Ό ν™œμš©ν•˜λŠ” μ½”λ“œλŠ” λ”°λ‘œ qt νŒŒμΌμ—μ„œ μΆ”κ°€ν•  건 μ—†κ³  μ½”λ“œ λͺ‡ μ€„λ§Œ μΆ”κ°€ν•˜λ©΄ λœλ‹€.

μš°μ„  μƒˆλ‘œ μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ 객체가 μ΄ˆκΈ°ν™”λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— __init__ ν•¨μˆ˜μ— μ•„λž˜μ˜ μ½”λ“œλ₯Ό μΆ”κ°€ν•œλ‹€.

        self.filter_te = self.findChild(QTextEdit, 'filter_te')

 

 

그리고 뢄석을 μ‹€ν–‰ν•˜λŠ” λ²„νŠΌμΈ [st_btn]을 μœ„ν•΄ μž‘μ„±ν•œ ν•¨μˆ˜ start_analyze_data에 filter_te에 μž‘μ„±λœ ν…μŠ€νŠΈλ₯Ό κ°€μ Έμ™€μ„œ μž…λ ₯ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ€€λ‹€.

        names = self.filter_te.toPlainText()
        names = names.split()

ν•΄λ‹Ή μ½”λ“œλ₯Ό μΆ”κ°€ν•΄μ£Όλ©΄ start_analyze_data ν•¨μˆ˜μ—μ„œ μ™„μ„±λ˜λŠ” μ½”λ“œ 값은 μ•„λž˜μ™€ κ°™λ‹€.

        if self.selected_value == 'μ‚¬μš©μžλ³„ λŒ€ν™” λΉˆλ„':
            self.fig = count_messages_by_name(self.refined_data)
            self.plot_pixmap()
        elif self.selected_value == 'μ‚¬μš©μžλ³„ 이λͺ¨ν‹°μ½˜ μ‚¬μš© λΉˆλ„':
            self.fig = count_emoticon_usage(self.refined_data, '이λͺ¨ν‹°μ½˜')
            self.plot_pixmap()
        elif self.selected_value == 'μ‚¬μš©μžλ³„ 평균 λ‹΅λ³€ μ‹œκ°„':
            self.fig = calculate_response_time(self.refined_data)
            self.plot_pixmap()
        elif self.selected_value == 'μ‚¬μš©μžλ³„ ν™œλ™ μ‹œκ°„λŒ€':
            self.fig = analyze_activity_by_time(self.refined_data, names)
            self.plot_pixmap()

names 값을 μ •μ˜ν•΄μ€¬κΈ° λ•Œλ¬Έμ— 'μ‚¬μš©μžλ³„ ν™œλ™ μ‹œκ°„λŒ€' ν•¨μˆ˜μ—μ„œ names λ₯Ό ν™œμš©ν•  수 μžˆλ‹€. 

그리고 λ‹€λ₯Έ κΈ°λŠ₯ κ°’μ—μ„œλŠ” μ •μ˜ μ•ˆλ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— names 값에 영ν–₯을 λ°›μ§€ μ•ŠλŠ”λ‹€.

 

λ§ˆμ§€λ§‰μœΌλ‘œ κ²°κ³Ό 화면을 리셋할 λ•Œ filter_te에 μž‘μ„±λœ 값도 ν•¨κ»˜ λ¦¬μ…‹λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— reset_canvas ν•¨μˆ˜μ— 

        self.filter_te.clear()

ν•΄λ‹Ή μ½”λ“œλ₯Ό μΆ”κ°€ν•΄μ€€λ‹€.

 

μ΄λ ‡κ²Œν•˜λ©΄ 필터링 κΈ°λŠ₯에 λŒ€ν•œ ν•¨μˆ˜ 연결은 μ™„μ„±λœλ‹€.

 

#5. λΆ„석 κ²°κ³Ό μ΄λ―Έμ§€ λ‹€μš΄λ‘œλ“œ λ²„νŠΌ - down_btn

좜λ ₯ κ²°κ³Ό 값을 GUIμ—μ„œ ν™•μΈν•˜κ³  μ΄λ―Έμ§€λ‘œλ„ λ‹€μš΄λ°›μ„ 수 μžˆλŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±ν•œλ‹€.ν•¨μˆ˜λͺ…은 download_image μΈλ° 사싀 ν•΄λ‹Ή 뢀뢄은 μž‘μ„±μ„ μ•„μ˜ˆ λͺ°λΌμ„œ gptκ°€ μž‘μ„±ν•΄μ€€λŒ€λ‘œ μ μš©ν–ˆλ”λ‹ˆ λ˜μ—ˆλ‹€.

    def download_image(self):
        file_path, _ = QFileDialog.getSaveFileName(self, "이미지 μ €μž₯", "", "PNG Files (*.png);;All Files (*)")
        if file_path:
            self.fig.savefig(file_path, format='png')
  • QFileDialog.getSaveFileName은 μ‚¬μš©μžκ°€ νŒŒμΌμ„ μ €μž₯ν•  μœ„μΉ˜μ™€ 이름을 선택할 수 μžˆλ„λ‘ 파일 μ €μž₯ λŒ€ν™” μƒμžλ₯Ό ν‘œμ‹œν•œλ‹€.
  • "이미지 μ €μž₯" : 파일 λŒ€ν™” μƒμž 제λͺ©μœΌλ‘œ μ‚¬μš©λœλ‹€.
  • " PNG Files (*.png);;All Files (*)" : 파일 ν˜•μ‹ ν•„ν„°λ₯Ό μ§€μ •ν•œλ‹€. μ—¬κΈ°μ„œλŠ” PNG 파일만 선택할 수 μžˆλ„λ‘ ν•˜κ³ , λͺ¨λ“  파일 ν˜•μ‹λ„ 선택할 수 있게 ν•œλ‹€.
  • if file_pathλ₯Ό μž‘μ„±ν•˜μ—¬ μ‚¬μš©μžκ°€ 파일 경둜λ₯Ό μ„ νƒν–ˆλ‹€λ©΄ 쑰건문이 μ‹€ν–‰λ˜λ„λ‘ μ„€μ •ν•œλ‹€.
  • file_path둜 μ§€μ •λœ κ²½λ‘œμ— 이미지λ₯Ό PNG ν˜•μ‹μœΌλ‘œ μ €μž₯ν•œλ‹€. 

 

그리고 λ§ˆμ§€λ§‰μœΌλ‘œ ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό qt의 객체인 down_btn μœ„μ ―μ— μ—°κ²°ν•΄μ€€λ‹€.

(__init__ μ•ˆμ—)

        self.down_btn.clicked.connect(self.download_image)

 

μ΄λ ‡κ²Œν•˜λ©΄ λͺ¨λ“  ν•¨μˆ˜ μž…λ ₯은 λλ‚œλ‹€. 

 

μž…λ ₯ν•œ ν•¨μˆ˜μ™€ 메인 μ„ μ–Έ ν•¨μˆ˜λ₯Ό ν•¨κ»˜ μ‹€ν–‰ν•˜λ©΄ λ™μž‘ν•˜λŠ” GUIλ₯Ό 확인할 수 μžˆλ‹€.

 

λ§ˆμ§€λ§‰ κ²Œμ‹œκΈ€μ— λ™μž‘ν•˜λŠ” κ²°κ³Όλ¬Ό μ˜μƒμ„ 첨뢀할 μ˜ˆμ •μ΄λ‹€.

λŒ“κΈ€μˆ˜0