벨트 CLI 스킬 설치: npx skills add belt-sh/cli
데이터 시각화은(는) 무엇을 하나요?
inference.sh CLI를 통해 명확하고 효과적인 데이터 시각화를 생성하세요.
빠른 시작
inference.sh CLI(belt) 필요. 설치 안내
belt login
belt app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.use(\"Agg\")\n\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]\nrevenue = [42, 48, 55, 61, 72, 89]\n\nfig, ax = plt.subplots(figsize=(10, 6))\nax.bar(months, revenue, color=\"#3b82f6\", width=0.6)\nax.set_ylabel(\"Revenue ($K)\")\nax.set_title(\"Monthly Revenue Growth\", fontweight=\"bold\")\nfor i, v in enumerate(revenue):\n ax.text(i, v + 1, f\"${v}K\", ha=\"center\", fontweight=\"bold\")\nplt.tight_layout()\nplt.savefig(\"revenue.png\", dpi=150)\nprint(\"Saved\")"}'
차트 선택 가이드
어떤 데이터에 어떤 차트를 사용할까?
| 데이터 관계 | 최적 차트 | 절대 사용 금지 |
|---|
| 시간에 따른 변화 | 꺾은선 차트 | 파이 차트 |
| 범주 비교 | 막대 차트 (범주가 많으면 가로) | 꺾은선 차트 |
| 전체 대비 부분 | 누적 막대, 트리맵 | 파이 차트 (논란의 여지 있지만, 막대가 항상 더 명확) |
| 분포 | 히스토그램, 상자 그림 | 막대 차트 |
| 상관관계 | 산점도 | 막대 차트 |
| 순위 | 가로 막대 차트 | 세로 막대, 파이 |
| 지리적 | 코로플레스 지도 | 막대 차트 |
| 시간에 따른 구성 | 누적 영역 차트 | 여러 개의 파이 차트 |
| 단일 지표 | 큰 숫자 (KPI 카드) | 모든 차트 (과잉) |
| 흐름 / 프로세스 | 생키 다이어그램 | 막대 차트 |
파이 차트의 문제점
파이 차트는 거의 항상 잘못된 선택입니다:
❌ 파이 차트 문제점:
- 비슷한 크기의 조각 비교가 어려움
- 5-6개 이상의 범주를 표시할 수 없음
- 3D 파이 차트는 항상 잘못됨
- 정확한 값을 읽는 것이 불가능
✅ 대신 사용할 것:
- 가로 막대 차트 (쉬운 비교)
- 누적 막대 (전체 대비 부분)
- 트리맵 (계층적 부분)
- 그냥 표 (정밀도가 중요할 때)
디자인 규칙
축
| 규칙 | 이유 |
|---|
| Y축은 항상 0에서 시작 (막대 차트) | 잘못된 시각적 정보를 방지 |
| 꺾은선 차트는 0 위에서 시작 가능 | 절대값이 아닌 변화를 보여줄 때 |
| 두 축 모두 레이블 표시 | 독자가 단위를 추측하지 않아도 됨 |
| 불필요한 격자선 제거 | 시각적 잡음 감소 |
| 가로 레이블 사용 | 세로 텍스트는 읽기 어려움 |
| 막대 차트는 값 기준 정렬 | 이유가 없다면 알파벳순 사용 금지 |
색상
| 원칙 | 적용 |
|---|
| 차트당 최대 5-7색 | 그 이상은 읽기 어려움 |
| 하나만 강조 | 나머지는 회색, 집중할 항목에 색상 |
| 순차형 (크기) | 낮음 → 높음: 밝음 → 어두움 |
| 발산형 (양/음수) | 빨강 ← 중립 → 파랑 |
| 범주형 (그룹) | 구별되는 색조, 비슷한 명도 |
| 색맹 친화적 | 빨강/초록만 사용 금지—도형이나 레이블 추가 |
| 일관된 의미 | 파랑 = 매출이면, 모든 곳에서 파랑 유지 |
좋은 색상 팔레트
sequential = ["#eff6ff", "#bfdbfe", "#60a5fa", "#2563eb", "#1d4ed8"]
diverging = ["#ef4444", "#f87171", "#d1d5db", "#34d399", "#10b981"]
categorical = ["#3b82f6", "#f59e0b", "#10b981", "#8b5cf6", "#ef4444"]
cb_safe = ["#0077BB", "#33BBEE", "#009988", "#EE7733", "#CC3311"]
텍스트 및 레이블
| 요소 | 규칙 |
|---|
| 제목 | 데이터 유형이 아닌 인사이트를 표시. "2분기 매출 2배 증가" ("2분기 매출 차트" 아님) |
| 주석 | 주요 데이터 포인트를 차트에 직접 표시 |
| 범례 | 가능하면 피하고, 차트 선/막대에 직접 레이블 지정 |
| 글꼴 크기 | 최소 12px, 프레젠테이션은 14px 이상 |
| 숫자 형식 | 큰 숫자는 K, M, B 사용 (42,000이 아닌 42K) |
| 데이터 레이블 | 정확한 값이 중요할 때 막대/포인트에 추가 |
차트 레시피
꺾은선 차트 (시계열)
belt app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.use(\"Agg\")\n\nfig, ax = plt.subplots(figsize=(12, 6))\nfig.patch.set_facecolor(\"white\")\n\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\nthis_year = [120, 135, 148, 162, 178, 195, 210, 228, 245, 268, 290, 320]\nlast_year = [95, 102, 108, 115, 122, 130, 138, 145, 155, 165, 178, 190]\n\nax.plot(months, this_year, color=\"#3b82f6\", linewidth=2.5, marker=\"o\", markersize=6, label=\"2024\")\nax.plot(months, last_year, color=\"#94a3b8\", linewidth=2, linestyle=\"--\", label=\"2023\")\nax.fill_between(range(len(months)), last_year, this_year, alpha=0.1, color=\"#3b82f6\")\n\nax.annotate(\"$320K\", xy=(11, 320), fontsize=14, fontweight=\"bold\", color=\"#3b82f6\")\nax.annotate(\"$190K\", xy=(11, 190), fontsize=12, color=\"#94a3b8\")\n\nax.set_ylabel(\"Revenue ($K)\", fontsize=12)\nax.set_title(\"Revenue grew 68% year-over-year\", fontsize=16, fontweight=\"bold\")\nax.legend(fontsize=12)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.grid(axis=\"y\", alpha=0.3)\nplt.tight_layout()\nplt.savefig(\"line-chart.png\", dpi=150)\nprint(\"Saved\")"}'
가로 막대 차트 (비교)
belt app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.use(\"Agg\")\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\ncategories = [\"Email\", \"Social\", \"SEO\", \"Paid Ads\", \"Referral\", \"Direct\"]\nvalues = [12, 18, 35, 22, 8, 5]\ncolors = [\"#94a3b8\"] * len(values)\ncolors[2] = \"#3b82f6\" # Highlight the winner\n\n# Sort by value\nsorted_pairs = sorted(zip(values, categories, colors))\nvalues, categories, colors = zip(*sorted_pairs)\n\nax.barh(categories, values, color=colors, height=0.6)\nfor i, v in enumerate(values):\n ax.text(v + 0.5, i, f\"{v}%\", va=\"center\", fontsize=12, fontweight=\"bold\")\n\nax.set_xlabel(\"% of Total Traffic\", fontsize=12)\nax.set_title(\"SEO drives the most traffic\", fontsize=16, fontweight=\"bold\")\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nplt.tight_layout()\nplt.savefig(\"bar-chart.png\", dpi=150)\nprint(\"Saved\")"}'
KPI / 큰 숫자 카드
belt app run infsh/html-to-image --input '{
"html": "<div style=\"display:flex;gap:20px;padding:20px;background:white;font-family:system-ui\"><div style=\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\"><p style=\"color:#64748b;font-size:14px;margin:0\">Monthly Revenue</p><p style=\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\">$89K</p><p style=\"color:#22c55e;font-size:14px;margin:0\">↑ 23% vs last month</p></div><div style=\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\"><p style=\"color:#64748b;font-size:14px;margin:0\">Active Users</p><p style=\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\">12.4K</p><p style=\"color:#22c55e;font-size:14px;margin:0\">↑ 8% vs last month</p></div><div style=\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\"><p style=\"color:#64748b;font-size:14px;margin:0\">Churn Rate</p><p style=\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\">2.1%</p><p style=\"color:#ef4444;font-size:14px;margin:0\">↑ 0.3% vs last month</p></div></div>"
}'
히트맵
belt app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt\nimport numpy as np\nimport matplotlib\nmatplotlib.use(\"Agg\")\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\ndays = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\nhours = [\"9AM\", \"10AM\", \"11AM\", \"12PM\", \"1PM\", \"2PM\", \"3PM\", \"4PM\", \"5PM\"]\ndata = np.random.randint(10, 100, size=(len(hours), len(days)))\ndata[2][1] = 95 # Tuesday 11AM peak\ndata[2][3] = 88 # Thursday 11AM\n\nim = ax.imshow(data, cmap=\"Blues\", aspect=\"auto\")\nax.set_xticks(range(len(days)))\nax.set_yticks(range(len(hours)))\nax.set_xticklabels(days, fontsize=12)\nax.set_yticklabels(hours, fontsize=12)\n\nfor i in range(len(hours)):\n for j in range(len(days)):\n color = \"white\" if data[i][j] > 60 else \"black\"\n ax.text(j, i, data[i][j], ha=\"center\", va=\"center\", fontsize=10, color=color)\n\nax.set_title(\"Website Traffic by Day & Hour\", fontsize=16, fontweight=\"bold\")\nplt.colorbar(im, label=\"Visitors\")\nplt.tight_layout()\nplt.savefig(\"heatmap.png\", dpi=150)\nprint(\"Saved\")"}'
데이터 스토리텔링
서사 구조
| 단계 | 설명 | 예시 |
|---|
| 1. 맥락 | 독자가 알아야 할 배경 설정 | "우리는 월별 고객 획득 비용을 추적합니다" |
| 2. 긴장감 | 문제나 변화를 보여줌 | "3분기 CAC가 40% 증가했습니다" |
| 3. 해결 | 인사이트나 해결책 제시 | "하지만 LTV가 80% 증가하여 유닛 경제성이 개선되었습니다" |
인사이트 중심의 제목
❌ 설명적 제목 (차트가 보여주는 것):
"제품군별 3분기 매출"
"2024년 월간 활성 사용자"
"고객 만족도 설문 조사 결과"
✅ 인사이트 중심 제목 (차트가 의미하는 것):
"엔터프라이즈 제품이 매출 성장의 70%를 견인"
"무료 티어 출시 후 사용자 성장 가속화"
"고객 지원 응답 시간이 만족도의 1순위 요인"
주석 기법
| 기법 | 사용 시기 |
|---|
| 호출 레이블 | 특정 데이터 포인트 강조 ("최고: 320K") |
| 참조선 | 목표/벤치마크 표시 ("목표: 100K") |
| 음영 영역 | 기간 표시 ("제품 출시 기간") |
| 화살표 + 텍스트 | 추세 변화에 주목 유도 |
| 이전/이후 선 | 이벤트의 영향 표시 |
다크 모드 차트
belt app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.use(\"Agg\")\n\n# Dark theme\nplt.rcParams.update({\n \"figure.facecolor\": \"#0f172a\",\n \"axes.facecolor\": \"#0f172a\",\n \"axes.edgecolor\": \"#334155\",\n \"axes.labelcolor\": \"white\",\n \"text.color\": \"white\",\n \"xtick.color\": \"white\",\n \"ytick.color\": \"white\",\n \"grid.color\": \"#1e293b\"\n})\n\nfig, ax = plt.subplots(figsize=(12, 6))\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]\nvalues = [45, 52, 58, 72, 85, 98]\n\nax.plot(months, values, color=\"#818cf8\", linewidth=3, marker=\"o\", markersize=8)\nax.fill_between(range(len(months)), values, alpha=0.15, color=\"#818cf8\")\nax.set_title(\"MRR Growth: On track for $100K\", fontsize=18, fontweight=\"bold\")\nax.set_ylabel(\"MRR ($K)\", fontsize=13)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.grid(axis=\"y\", alpha=0.2)\n\nfor i, v in enumerate(values):\n ax.annotate(f\"${v}K\", (i, v), textcoords=\"offset points\", xytext=(0, 12), ha=\"center\", fontsize=11, fontweight=\"bold\")\n\nplt.tight_layout()\nplt.savefig(\"dark-chart.png\", dpi=150, facecolor=\"#0f172a\")\nprint(\"Saved\")"}'
일반적인 실수
| 실수 | 문제점 | 해결책 |
|---|
| 파이 차트 | 비교 어려움, 항상 오해의 소지 | 막대 차트 또는 트리맵 사용 |
| Y축 0 미시작 (막대 차트) | 차이를 과장 | 막대는 0 시작, 선은 절단 가능 |
| 너무 많은 색상 | 시각적 잡음, 혼란 | 최대 5-7색, 중요한 것만 강조 |
| 제목 없음 또는 일반 제목 | 독자가 인사이트를 모름 | 제목 = 핵심 메시지, 데이터 유형이 아님 |
| 3D 차트 | 데이터 왜곡, 비전문적 | 항상 2D 사용 |
| 이중 Y축 | 오해의 소지, 읽기 어려움 | 두 개의 개별 차트 사용 |
| 막대 차트 알파벳순 정렬 | 스토리를 숨김 | 값 기준 정렬 (큰 것 먼저) |
| 축 레이블 없음 | 독자가 해석 불가 | 항상 단위와 함께 레이블 표시 |
| 차트 장식 (장식 요소) | 데이터에서 주의 분산 | 정보를 전달하지 않는 모든 것 제거 |
| 빨강/초록만 사용한 색상 코딩 | 색맹 사용자가 읽을 수 없음 | 도형, 패턴 또는 색맹 친화적 팔레트 사용 |
관련 스킬
npx skills add inference-sh/skills@pitch-deck-visuals
npx skills add inference-sh/skills@technical-blog-writing
npx skills add inference-sh/skills@competitor-teardown
모든 앱 보기: belt app list