name: 数据可视化
description: “数据可视化,包含图表选择、颜色理论和注释最佳实践。涵盖图表类型(条形图、折线图、散点图、热力图)、坐标轴规则和用数据讲故事。用于:图表、图形、仪表板、报告、演示、信息图、数据故事。触发词:数据可视化、图表、图形、数据图表、条形图、折线图、散点图、数据可视化、可视化、仪表板图表、信息图数据、数据演示、图表设计、绘图、热力图、饼图替代”
allowed-tools: Bash(infsh *)
数据可视化
通过 inference.sh CLI 创建清晰有效的数据可视化。
快速开始
curl -fsSL https://cli.inference.sh | sh && infsh login
# 使用 Python 生成图表
infsh app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt
import matplotlib
matplotlib.use(\"Agg\")
months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]
revenue = [42, 48, 55, 61, 72, 89]
fig, ax = plt.subplots(figsize=(10, 6))
ax.bar(months, revenue, color=\"#3b82f6\", width=0.6)
ax.set_ylabel(\"收入($K)\")
ax.set_title(\"月度收入增长\", fontweight=\"bold\")
for i, v in enumerate(revenue):
ax.text(i, v + 1, f\"${v}K\", ha=\"center\", fontweight=\"bold\")
plt.tight_layout()
plt.savefig(\"revenue.png\", dpi=150)
print(\"已保存\")"
}'
安装说明: 安装脚本 仅检测您的操作系统/架构,从 dist.inference.sh 下载匹配的二进制文件,并验证其 SHA-256 校验和。无需提升权限或后台进程。提供手动安装和验证。
图表选择指南
哪种图表适合哪种数据?
| 数据关系 |
最佳图表 |
永不使用 |
| 随时间变化 |
折线图 |
饼图 |
| 比较类别 |
条形图(类别多时用水平条形) |
折线图 |
| 部分与整体 |
堆叠条形图、树状图 |
饼图(有争议,但条形图总是更清晰) |
| 分布 |
直方图、箱形图 |
条形图 |
| 相关性 |
散点图 |
条形图 |
| 排名 |
水平条形图 |
垂直条形图、饼图 |
| 地理 |
等值区域地图 |
条形图 |
| 随时间变化的组成 |
堆叠面积图 |
多个饼图 |
| 单一指标 |
大数字(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"]
文本和标签
| 元素 |
规则 |
| 标题 |
陈述洞察,而非数据类型。“第二季度收入翻倍”而非“第二季度收入图表” |
| 注释 |
直接在图表上标注关键数据点 |
| 图例 |
尽量避免 — 直接在图表线/条上标记 |
| 字体大小 |
最小12px,演示时14px+ |
| 数字格式 |
大数字用K、M、B(42K而非42,000) |
| 数据标签 |
当精确值重要时添加到条形/点 |
图表配方
折线图(时间序列)
infsh app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt
import matplotlib
matplotlib.use(\"Agg\")
fig, ax = plt.subplots(figsize=(12, 6))
fig.patch.set_facecolor(\"white\")
months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]
this_year = [120, 135, 148, 162, 178, 195, 210, 228, 245, 268, 290, 320]
last_year = [95, 102, 108, 115, 122, 130, 138, 145, 155, 165, 178, 190]
ax.plot(months, this_year, color=\"#3b82f6\", linewidth=2.5, marker=\"o\", markersize=6, label=\"2024\")
ax.plot(months, last_year, color=\"#94a3b8\", linewidth=2, linestyle=\"--\", label=\"2023\")
ax.fill_between(range(len(months)), last_year, this_year, alpha=0.1, color=\"#3b82f6\")
ax.annotate(\"$320K\", xy=(11, 320), fontsize=14, fontweight=\"bold\", color=\"#3b82f6\")
ax.annotate(\"$190K\", xy=(11, 190), fontsize=12, color=\"#94a3b8\")
ax.set_ylabel(\"收入($K)\", fontsize=12)
ax.set_title(\"收入同比增长68%\", fontsize=16, fontweight=\"bold\")
ax.legend(fontsize=12)
ax.spines[\"top\"].set_visible(False)
ax.spines[\"right\"].set_visible(False)
ax.grid(axis=\"y\", alpha=0.3)
plt.tight_layout()
plt.savefig(\"line-chart.png\", dpi=150)
print(\"已保存\")"
}'
水平条形图(比较)
infsh app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt
import matplotlib
matplotlib.use(\"Agg\")
fig, ax = plt.subplots(figsize=(10, 6))
categories = [\"邮件\", \"社交\", \"SEO\", \"付费广告\", \"推荐\", \"直接访问\"]
values = [12, 18, 35, 22, 8, 5]
colors = [\"#94a3b8\"] * len(values)
colors[2] = \"#3b82f6\" # 突出显示获胜者
# 按值排序
sorted_pairs = sorted(zip(values, categories, colors))
values, categories, colors = zip(*sorted_pairs)
ax.barh(categories, values, color=colors, height=0.6)
for i, v in enumerate(values):
ax.text(v + 0.5, i, f\"{v}%\", va=\"center\", fontsize=12, fontweight=\"bold\")
ax.set_xlabel(\"总流量百分比\", fontsize=12)
ax.set_title(\"SEO驱动最多流量\", fontsize=16, fontweight=\"bold\")
ax.spines[\"top\"].set_visible(False)
ax.spines[\"right\"].set_visible(False)
plt.tight_layout()
plt.savefig(\"bar-chart.png\", dpi=150)
print(\"已保存\")"
}'
KPI / 大数字卡片
infsh 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\">月度收入</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% 对比上月</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\">活跃用户</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% 对比上月</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\">流失率</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% 对比上月</p></div></div>"
}'
热力图
infsh app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt
import numpy as np
import matplotlib
matplotlib.use(\"Agg\")
fig, ax = plt.subplots(figsize=(10, 6))
days = [\"周一\", \"周二\", \"周三\", \"周四\", \"周五\", \"周六\", \"周日\"]
hours = [\"9AM\", \"10AM\", \"11AM\", \"12PM\", \"1PM\", \"2PM\", \"3PM\", \"4PM\", \"5PM\"]
data = np.random.randint(10, 100, size=(len(hours), len(days)))
data[2][1] = 95 # 周二11AM高峰
data[2][3] = 88 # 周四11AM
im = ax.imshow(data, cmap=\"Blues\", aspect=\"auto\")
ax.set_xticks(range(len(days)))
ax.set_yticks(range(len(hours)))
ax.set_xticklabels(days, fontsize=12)
ax.set_yticklabels(hours, fontsize=12)
for i in range(len(hours)):
for j in range(len(days)):
color = \"white\" if data[i][j] > 60 else \"black\"
ax.text(j, i, data[i][j], ha=\"center\", va=\"center\", fontsize=10, color=color)
ax.set_title(\"网站流量按天和小时分布\", fontsize=16, fontweight=\"bold\")
plt.colorbar(im, label=\"访客数\")
plt.tight_layout()
plt.savefig(\"heatmap.png\", dpi=150)
print(\"已保存\")"
}'
用数据讲故事
叙事弧线
| 步骤 |
做什么 |
示例 |
| 1. 上下文 |
设置读者需要知道的内容 |
“我们每月跟踪客户获取成本” |
| 2. 张力 |
展示问题或变化 |
“CAC在第三季度增加了40%” |
| 3. 解决 |
展示洞察或解决方案 |
“但LTV增加了80%,因此单位经济改善” |
标题即洞察
❌ 描述性标题(图表显示什么):
“第三季度按产品线收入”
“2024月度活跃用户”
“客户满意度调查结果”
✅ 洞察标题(图表含义):
“企业产品驱动70%的收入增长”
“免费层发布后用户增长加速”
“支持响应时间是满意度第一驱动因素”
注释技术
| 技术 |
何时使用 |
| 标注标签 |
突出特定数据点(“峰值:320K”) |
| 参考线 |
显示目标/基准(“目标:100K”) |
| 阴影区域 |
标记时间段(“产品发布窗口”) |
| 箭头 + 文本 |
吸引注意力到趋势变化 |
| 之前/之后线 |
展示事件影响 |
暗色模式图表
infsh app run infsh/python-executor --input '{
"code": "import matplotlib.pyplot as plt
import matplotlib
matplotlib.use(\"Agg\")
# 暗色主题
plt.rcParams.update({
\"figure.facecolor\": \"#0f172a\",
\"axes.facecolor\": \"#0f172a\",
\"axes.edgecolor\": \"#334155\",
\"axes.labelcolor\": \"white\",
\"text.color\": \"white\",
\"xtick.color\": \"white\",
\"ytick.color\": \"white\",
\"grid.color\": \"#1e293b\"
})
fig, ax = plt.subplots(figsize=(12, 6))
months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]
values = [45, 52, 58, 72, 85, 98]
ax.plot(months, values, color=\"#818cf8\", linewidth=3, marker=\"o\", markersize=8)
ax.fill_between(range(len(months)), values, alpha=0.15, color=\"#818cf8\")
ax.set_title(\"MRR增长:迈向100K目标\", fontsize=18, fontweight=\"bold\")
ax.set_ylabel(\"MRR($K)\", fontsize=13)
ax.spines[\"top\"].set_visible(False)
ax.spines[\"right\"].set_visible(False)
ax.grid(axis=\"y\", alpha=0.2)
for i, v in enumerate(values):
ax.annotate(f\"${v}K\", (i, v), textcoords=\"offset points\", xytext=(0, 12), ha=\"center\", fontsize=11, fontweight=\"bold\")
plt.tight_layout()
plt.savefig(\"dark-chart.png\", dpi=150, facecolor=\"#0f172a\")
print(\"已保存\")"
}'
常见错误
| 错误 |
问题 |
修复 |
| 饼图 |
难以比较,总是误导 |
使用条形图或树状图 |
| 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
浏览所有应用:infsh app list