๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ก Data Analysis/๐Ÿ“‚ Project - Analysis of KakaoTalk (end)

[QT][Python] ํ•จ์ˆ˜์™€ QT ์—ฐ๊ฒฐํ•˜๊ธฐ (4)

by Sun A 2024. 8. 12.
#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๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋งˆ์ง€๋ง‰ ๊ฒŒ์‹œ๊ธ€์— ๋™์ž‘ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฌผ ์˜์ƒ์„ ์ฒจ๋ถ€ํ•  ์˜ˆ์ •์ด๋‹ค.