Skip to content

Instantly share code, notes, and snippets.

@allieus
Created October 8, 2025 14:50
Show Gist options
  • Save allieus/c82e974a807075940e99728e71ea2f27 to your computer and use it in GitHub Desktop.
Save allieus/c82e974a807075940e99728e71ea2f27 to your computer and use it in GitHub Desktop.
ABC부트캠프 Python 강의 - Excel 대시보드 자동 생성기 (xlwings)
# ABC부트캠프 Python 강의 - Excel 대시보드 자동 생성기
# xlwings와 Claude Code를 활용한 실습
import xlwings as xw
import pandas as pd
from pathlib import Path
# 설정: 대시보드 색상 테마
THEME_COLORS = {
"header_bg": "#2E5984", # 진한 파란색 (헤더 배경)
"header_text": "#FFFFFF", # 흰색 (헤더 텍스트)
"title_bg": "#4472C4", # 밝은 파란색 (제목 배경)
"chart_color1": "#5B9BD5", # 차트 색상 1
"chart_color2": "#ED7D31", # 차트 색상 2
"chart_color3": "#A5A5A5", # 차트 색상 3
"grid_line": "#D9D9D9" # 그리드 라인
}
class ExcelDashboardGenerator:
"""Excel 대시보드 자동 생성 클래스"""
def __init__(self, data_path):
"""
초기화
Args:
data_path: 엑셀 데이터 파일 경로
"""
self.data_path = Path(data_path)
self.app = None
self.wb = None
self.df = None
def load_data(self):
"""데이터 로드"""
print("📂 데이터 로드 중...")
self.df = pd.read_excel(self.data_path)
print(f"✅ {len(self.df)}개 행 로드 완료")
return self.df
def create_workbook(self, visible=True):
"""새 워크북 생성"""
print("📝 Excel 워크북 생성 중...")
self.app = xw.App(visible=visible)
self.wb = self.app.books.add()
print("✅ 워크북 생성 완료")
def create_dashboard_template(self):
"""대시보드 템플릿 생성"""
print("🎨 대시보드 템플릿 생성 중...")
# 시트 이름 변경
dashboard_sheet = self.wb.sheets[0]
dashboard_sheet.name = "대시보드"
# 헤더 영역 (A1:H1)
header_range = dashboard_sheet.range('A1:H1')
header_range.merge()
header_range.value = "🎮 글로벌 게임 판매 대시보드"
header_range.color = THEME_COLORS["header_bg"]
header_range.api.Font.Color = 0xFFFFFF # 흰색 텍스트
header_range.api.Font.Size = 20
header_range.api.Font.Bold = True
header_range.api.HorizontalAlignment = -4108 # 가운데 정렬
dashboard_sheet.range('A1').row_height = 40
# 차트 제목 영역 설정
chart_titles = {
'A3:D3': '📊 장르별 판매량',
'E3:H3': '🏆 Top 10 배급사',
'A13:D13': '📅 연도별 판매 추이',
'E13:H13': '🎯 플랫폼별 분포'
}
for cell_range, title in chart_titles.items():
title_cell = dashboard_sheet.range(cell_range)
title_cell.merge()
title_cell.value = title
title_cell.color = THEME_COLORS["title_bg"]
title_cell.api.Font.Color = 0xFFFFFF
title_cell.api.Font.Size = 14
title_cell.api.Font.Bold = True
title_cell.api.HorizontalAlignment = -4108
print("✅ 템플릿 생성 완료")
def add_data_sheet(self):
"""데이터 시트 추가"""
print("📊 데이터 시트 추가 중...")
# 새 시트 추가
data_sheet = self.wb.sheets.add("원본데이터", after=self.wb.sheets[-1])
# 데이터 붙여넣기
data_sheet.range('A1').value = self.df
# 헤더 스타일링
header_range = data_sheet.range(f'A1:{chr(65+len(self.df.columns)-1)}1')
header_range.color = THEME_COLORS["header_bg"]
header_range.api.Font.Color = 0xFFFFFF
header_range.api.Font.Bold = True
# 열 너비 자동 조정
data_sheet.autofit('c')
print("✅ 데이터 시트 추가 완료")
def create_genre_chart(self):
"""장르별 판매량 차트 생성"""
print("📈 장르별 판매량 차트 생성 중...")
# 장르별 판매량 집계
genre_sales = self.df.groupby('장르')['판매량_백만'].sum().sort_values(ascending=False)
# 피벗 시트 생성
pivot_sheet = self.wb.sheets.add("피벗_장르", after=self.wb.sheets[-1])
pivot_sheet.range('A1').value = "장르"
pivot_sheet.range('B1').value = "판매량"
pivot_sheet.range('A2').value = genre_sales.index.tolist()
pivot_sheet.range('B2').value = [[v] for v in genre_sales.values.tolist()]
# 차트 생성
dashboard_sheet = self.wb.sheets["대시보드"]
chart = dashboard_sheet.charts.add(left=dashboard_sheet.range('A4').left,
top=dashboard_sheet.range('A4').top,
width=280, height=200)
chart.set_source_data(pivot_sheet.range('A1:B' + str(len(genre_sales)+1)))
chart.chart_type = 'column_clustered' # 세로 막대형
chart.api[1].HasTitle = False
print("✅ 장르별 차트 완성")
def create_publisher_chart(self):
"""Top 10 배급사 차트 생성"""
print("📈 배급사 차트 생성 중...")
# 배급사별 판매량 Top 10
publisher_sales = self.df.groupby('배급사')['판매량_백만'].sum().sort_values(ascending=False).head(10)
# 피벗 시트 생성
pivot_sheet = self.wb.sheets.add("피벗_배급사", after=self.wb.sheets[-1])
pivot_sheet.range('A1').value = "배급사"
pivot_sheet.range('B1').value = "판매량"
pivot_sheet.range('A2').value = publisher_sales.index.tolist()
pivot_sheet.range('B2').value = [[v] for v in publisher_sales.values.tolist()]
# 차트 생성
dashboard_sheet = self.wb.sheets["대시보드"]
chart = dashboard_sheet.charts.add(left=dashboard_sheet.range('E4').left,
top=dashboard_sheet.range('E4').top,
width=280, height=200)
chart.set_source_data(pivot_sheet.range('A1:B11'))
chart.chart_type = 'bar_clustered' # 가로 막대형
chart.api[1].HasTitle = False
print("✅ 배급사 차트 완성")
def create_year_chart(self):
"""연도별 판매 추이 차트 생성"""
print("📈 연도별 추이 차트 생성 중...")
# 연도별 판매량 집계
year_sales = self.df.groupby('발행년도')['판매량_백만'].sum().sort_index()
# 피벗 시트 생성
pivot_sheet = self.wb.sheets.add("피벗_연도", after=self.wb.sheets[-1])
pivot_sheet.range('A1').value = "연도"
pivot_sheet.range('B1').value = "판매량"
pivot_sheet.range('A2').value = [[y] for y in year_sales.index.tolist()]
pivot_sheet.range('B2').value = [[v] for v in year_sales.values.tolist()]
# 차트 생성
dashboard_sheet = self.wb.sheets["대시보드"]
chart = dashboard_sheet.charts.add(left=dashboard_sheet.range('A14').left,
top=dashboard_sheet.range('A14').top,
width=280, height=200)
chart.set_source_data(pivot_sheet.range('A1:B' + str(len(year_sales)+1)))
chart.chart_type = 'line' # 꺾은선형
chart.api[1].HasTitle = False
print("✅ 연도별 차트 완성")
def create_platform_chart(self):
"""플랫폼별 분포 차트 생성"""
print("📈 플랫폼 차트 생성 중...")
# 플랫폼별 게임 수 집계
platform_count = self.df['플랫폼'].value_counts().head(8)
# 피벗 시트 생성
pivot_sheet = self.wb.sheets.add("피벗_플랫폼", after=self.wb.sheets[-1])
pivot_sheet.range('A1').value = "플랫폼"
pivot_sheet.range('B1').value = "게임 수"
pivot_sheet.range('A2').value = platform_count.index.tolist()
pivot_sheet.range('B2').value = [[v] for v in platform_count.values.tolist()]
# 차트 생성
dashboard_sheet = self.wb.sheets["대시보드"]
chart = dashboard_sheet.charts.add(left=dashboard_sheet.range('E14').left,
top=dashboard_sheet.range('E14').top,
width=280, height=200)
chart.set_source_data(pivot_sheet.range('A1:B' + str(len(platform_count)+1)))
chart.chart_type = 'pie' # 원형
chart.api[1].HasTitle = False
print("✅ 플랫폼 차트 완성")
def save_dashboard(self, output_path):
"""대시보드 저장"""
print(f"💾 대시보드 저장 중: {output_path}")
self.wb.save(output_path)
print("✅ 저장 완료!")
def close(self):
"""워크북 닫기"""
if self.wb:
self.wb.close()
if self.app:
self.app.quit()
def generate(self, output_path, visible=True):
"""
대시보드 전체 생성 프로세스
Args:
output_path: 출력 파일 경로
visible: Excel 창 표시 여부
"""
try:
# 1. 데이터 로드
self.load_data()
# 2. 워크북 생성
self.create_workbook(visible=visible)
# 3. 대시보드 템플릿 생성
self.create_dashboard_template()
# 4. 데이터 시트 추가
self.add_data_sheet()
# 5. 차트 생성
self.create_genre_chart()
self.create_publisher_chart()
self.create_year_chart()
self.create_platform_chart()
# 6. 저장
self.save_dashboard(output_path)
print("\n🎉 대시보드 생성 완료!")
print(f"📁 파일 위치: {output_path}")
except Exception as e:
print(f"❌ 오류 발생: {e}")
raise
finally:
# Excel은 사용자가 직접 닫을 수 있도록 자동 종료하지 않음
pass
# 메인 실행
if __name__ == "__main__":
# 샘플 데이터 경로
data_path = "game_sales_data.xlsx"
output_path = "게임판매_대시보드.xlsx"
# 대시보드 생성
generator = ExcelDashboardGenerator(data_path)
generator.generate(output_path, visible=True)
print("\n💡 Tip: Excel 창을 직접 닫으시면 됩니다!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment