mcpField
D
data-visualization

data-visualization

github.com/anthropics数据与数据库33.6k13.9k 次安装1 天前更新
代码仓库

关于 data-visualization

面向数据图表制作的数据可视化技能,提供图表选择建议和 Python 可视化代码模式,并涵盖设计与无障碍原则。

主要功能

  1. 01按数据关系选择图表
  2. 02Python 图表代码模式
  3. 03颜色与布局原则
  4. 04准确性和无障碍检查

适用场景

  1. 01为数据集选择图表
  2. 02使用 Python 或 Plotly 制作图表
  3. 03检查图表的无障碍性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anthropics/knowledge-work-plugins --skill data-visualization

安装后在 Claude Code 中输入/data-visualization确认已加载。

详细介绍

数据可视化技能

图表选择指南、Python 可视化代码模式、设计原则以及无障碍注意事项,用于创建有效的数据可视化。

图表选择指南

按数据关系选择
你要展示的内容最佳图表替代方案
随时间变化的趋势折线图面积图(如需展示累计值或构成)
跨类别比较垂直柱状图水平柱状图(类别较多时)、棒棒糖图
排名水平柱状图点图、斜率图(比较两个时期)
部分与整体的构成堆叠柱状图树状图(层级结构)、华夫饼图
随时间变化的构成堆叠面积图百分比堆叠柱状图(侧重比例)
分布直方图箱线图(比较各组)、小提琴图、条带图
相关性(2 个变量)散点图气泡图(以第 3 个变量作为大小)
相关性(多个变量)热力图(相关系数矩阵)配对图
地理模式分级统计地图气泡地图、六边形地图
流动 / 流程桑基图漏斗图(按顺序排列的阶段)
关系网络网络图弦图
实际表现与目标对比子弹图仪表盘(仅适用于单一 KPI)
同时展示多个 KPI小型多图包含多个独立图表的仪表板
不应使用某些图表的情况
  • 饼图:除非类别少于 6 个,且精确比例不如大致比较重要,否则应避免使用。人类很难准确比较角度,应改用柱状图。
  • 3D 图表:绝对避免。它们会扭曲感知,且不增加任何信息。
  • 双轴图表:需谨慎使用。它们可能暗示相关性,从而产生误导。如果使用,请清楚标注两个坐标轴。
  • 堆叠柱状图(类别较多):难以比较中间段的数值。请改用小型多图或分组柱状图。
  • 环形图:比饼图略好,但存在相同的根本问题。最多仅用于单一 KPI 展示。

Python 可视化代码模式

设置与样式
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import seaborn as sns
import pandas as pd
import numpy as np

# Professional style setup
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams.update({
    'figure.figsize': (10, 6),
    'figure.dpi': 150,
    'font.size': 11,
    'axes.titlesize': 14,
    'axes.titleweight': 'bold',
    'axes.labelsize': 11,
    'xtick.labelsize': 10,
    'ytick.labelsize': 10,
    'legend.fontsize': 10,
    'figure.titlesize': 16,
})

# Colorblind-friendly palettes
PALETTE_CATEGORICAL = ['#4C72B0', '#DD8452', '#55A868', '#C44E52', '#8172B3', '#937860']
PALETTE_SEQUENTIAL = 'YlOrRd'
PALETTE_DIVERGING = 'RdBu_r'
折线图(时间序列)
fig, ax = plt.subplots(figsize=(10, 6))

for label, group in df.groupby('category'):
    ax.plot(group['date'], group['value'], label=label, linewidth=2)

ax.set_title('Metric Trend by Category', fontweight='bold')
ax.set_xlabel('Date')
ax.set_ylabel('Value')
ax.legend(loc='upper left', frameon=True)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

# Format dates on x-axis
fig.autofmt_xdate()

plt.tight_layout()
plt.savefig('trend_chart.png', dpi=150, bbox_inches='tight')
柱状图(比较)
fig, ax = plt.subplots(figsize=(10, 6))

# Sort by value for easy reading
df_sorted = df.sort_values('metric', ascending=True)

bars = ax.barh(df_sorted['category'], df_sorted['metric'], color=PALETTE_CATEGORICAL[0])

# Add value labels
for bar in bars:
    width = bar.get_width()
    ax.text(width + 0.5, bar.get_y() + bar.get_height()/2,
            f'{width:,.0f}', ha='left', va='center', fontsize=10)

ax.set_title('Metric by Category (Ranked)', fontweight='bold')
ax.set_xlabel('Metric Value')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.tight_layout()
plt.savefig('bar_chart.png', dpi=150, bbox_inches='tight')
直方图(分布)
fig, ax = plt.subplots(figsize=(10, 6))

ax.hist(df['value'], bins=30, color=PALETTE_CATEGORICAL[0], edgecolor='white', alpha=0.8)

# Add mean and median lines
mean_val = df['value'].mean()
median_val = df['value'].median()
ax.axvline(mean_val, color='red', linestyle='--', linewidth=1.5, label=f'Mean: {mean_val:,.1f}')
ax.axvline(median_val, color='green', linestyle='--', linewidth=1.5, label=f'Median: {median_val:,.1f}')

ax.set_title('Distribution of Values', fontweight='bold')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.tight_layout()
plt.savefig('histogram.png', dpi=150, bbox_inches='tight')
热力图
fig, ax = plt.subplots(figsize=(10, 8))

# Pivot data for heatmap format
pivot = df.pivot_table(index='row_dim', columns='col_dim', values='metric', aggfunc='sum')

sns.heatmap(pivot, annot=True, fmt=',.0f', cmap='YlOrRd',
            linewidths=0.5, ax=ax, cbar_kws={'label': 'Metric Value'})

ax.set_title('Metric by Row Dimension and Column Dimension', fontweight='bold')
ax.set_xlabel('Column Dimension')
ax.set_ylabel('Row Dimension')

plt.tight_layout()
plt.savefig('heatmap.png', dpi=150, bbox_inches='tight')
小型多图
categories = df['category'].unique()
n_cats = len(categories)
n_cols = min(3, n_cats)
n_rows = (n_cats + n_cols - 1) // n_cols

fig, axes = plt.subplots(n_rows, n_cols, figsize=(5*n_cols, 4*n_rows), sharex=True, sharey=True)
axes = axes.flatten() if n_cats > 1 else [axes]

for i, cat in enumerate(categories):
    ax = axes[i]
    subset = df[df['category'] == cat]
    ax.plot(subset['date'], subset['value'], color=PALETTE_CATEGORICAL[i % len(PALETTE_CATEGORICAL)])
    ax.set_title(cat, fontsize=12)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)

# Hide empty subplots
for j in range(i+1, len(axes)):
    axes[j].set_visible(False)

fig.suptitle('Trends by Category', fontsize=14, fontweight='bold', y=1.02)
plt.tight_layout()
plt.savefig('small_multiples.png', dpi=150, bbox_inches='tight')
数字格式化辅助函数
def format_number(val, format_type='number'):
    """Format numbers for chart labels."""
    if format_type == 'currency':
        if abs(val) >= 1e9:
            return f'${val/1e9:.1f}B'
        elif abs(val) >= 1e6:
            return f'${val/1e6:.1f}M'
        elif abs(val) >= 1e3:
            return f'${val/1e3:.1f}K'
        else:
            return f'${val:,.0f}'
    elif format_type == 'percent':
        return f'{val:.1f}%'
    elif format_type == 'number':
        if abs(val) >= 1e9:
            return f'{val/1e9:.1f}B'
        elif abs(val) >= 1e6:
            return f'{val/1e6:.1f}M'
        elif abs(val) >= 1e3:
            return f'{val/1e3:.1f}K'
        else:
            return f'{val:,.0f}'
    return str(val)

# Usage with axis formatter
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x, p: format_number(x, 'currency')))
使用 Plotly 创建交互式图表
import plotly.express as px
import plotly.graph_objects as go

# Simple interactive line chart
fig = px.line(df, x='date', y='value', color='category',
              title='Interactive Metric Trend',
              labels={'value': 'Metric Value', 'date': 'Date'})
fig.update_layout(hovermode='x unified')
fig.write_html('interactive_chart.html')
fig.show()

# Interactive scatter with hover data
fig = px.scatter(df, x='metric_a', y='metric_b', color='category',
                 size='size_metric', hover_data=['name', 'detail_field'],
                 title='Correlation Analysis')
fig.show()

设计原则

颜色
  • 有目的地使用颜色:颜色应用于编码数据,而非装饰
  • 突出故事重点:用醒目的强调色标示关键洞察,其余内容使用灰色
  • 顺序数据:对有序数值使用单一色相的渐变(由浅到深)
  • 发散数据:对具有有意义中心点的数据,使用带中性中间色的双色相渐变
  • 分类数据:使用可区分的色相,最多 6-8 种,超过后会变得混乱
  • 避免仅依赖红/绿:约 8% 的男性存在红绿色盲。主要配色请使用蓝/橙组合
字体排版
  • 标题应点明洞察:"营收同比增长 23%" 优于 "按月营收"
  • 副标题补充背景:日期范围、已应用的筛选条件、数据来源
  • 坐标轴标签应易于阅读:若可能,避免旋转 90 度。应缩短或换行处理
  • 数据标签用于增加精确度:用于关键数据点,而非每一个柱子都标注
  • 注释用于突出重点:通过文字注释标注特定数据点
布局
  • 减少图表冗余元素:移除不承载信息的网格线、边框和背景
  • 有意义地排序:除非存在自然顺序(如月份、阶段),否则按数值排序类别,而非按字母顺序
  • 合适的宽高比:时间序列图宽度应大于高度(3:1 至 2:1);比较类图表可以更接近正方形
  • 留白很重要:不要把图表挤在一起,为每个可视化内容留出足够的空间
准确性
  • 柱状图从零开始:始终如此。从 95 到 100 的柱子会夸大 5% 的差异
  • 折线图可以使用非零基线:当变化范围具有实际意义时
  • 多个图表使用一致的刻度:比较多个图表时,使用相同的坐标轴范围
  • 展示不确定性:数据存在不确定性时,使用误差线、置信区间或范围
  • 为坐标轴添加标签:绝不让读者猜测数字的含义

无障碍注意事项

色盲
  • 切勿仅依靠颜色来区分数据系列
  • 添加图案填充、不同的线型(实线、虚线、点线)或直接标签
  • 使用色盲模拟器进行测试(例如 Coblis、Sim Daltonism)
  • 使用对色盲友好的调色板:sns.color_palette("colorblind")
屏幕阅读器
  • 添加替代文本,描述图表的关键结论
  • 在可视化图表旁提供数据表格作为替代内容
  • 使用语义化的标题和标签
通用无障碍
  • 数据元素与背景之间保持足够的对比度
  • 标签文字最小 10pt,标题文字最小 12pt
  • 避免仅通过空间位置传递信息(添加标签)
  • 考虑打印场景:图表在黑白打印下是否依然清晰?
无障碍检查清单

分享可视化图表之前:

  • 图表在无颜色的情况下依然可读(通过图案、标签或线型区分系列)
  • 在标准缩放级别下文字清晰可读
  • 标题描述的是洞察结论,而不仅仅是数据内容
  • 坐标轴已标注单位
  • 图例清晰,且位置不遮挡数据
  • 已注明数据来源和日期范围

评论

支持 Markdown