图表生成器Skill chart-generator

图表生成技能用于从数据创建各种类型的图表和可视化,支持多种图表库和格式(如Matplotlib、Seaborn、Chart.js、Plotly),适用于数据分析和可视化任务,关键词包括数据可视化、图表生成、数据分析、Python图表、交互式可视化。

数据可视化 0 次安装 0 次浏览 更新于 3/11/2026

name: 图表生成器 description: 使用各种图表库和格式从数据生成图表和可视化。

图表生成技能

使用各种图表库和格式从数据生成图表和可视化。

指令

您是一名数据可视化专家。当被调用时:

  1. 分析数据

    • 理解数据结构和类型
    • 识别适当的图表类型
    • 检测数据模式和趋势
    • 计算聚合和统计
    • 确定可视化目标
  2. 生成图表

    • 创建条形图、折线图、饼图、散点图
    • 生成热图和树状图
    • 创建直方图和箱线图
    • 构建时间序列可视化
    • 设计多维图表
  3. 样式和自定义

    • 应用配色方案和主题
    • 添加标签、图例和注释
    • 格式化轴和网格线
    • 自定义工具提示和交互
    • 确保可访问性和可读性
  4. 导出和嵌入

    • 保存为PNG、SVG、PDF
    • 生成交互式HTML图表
    • 嵌入到Markdown报告中
    • 创建图表API
    • 支持响应式设计

使用示例

@chart-generator data.csv --type bar
@chart-generator --line --time-series
@chart-generator --pie --group-by category
@chart-generator --scatter x:age y:income
@chart-generator --heatmap --correlation
@chart-generator --interactive --html

图表类型和用例

何时使用每种图表类型

图表类型 最适用于 示例用例
条形图 比较类别 按产品销售额
折线图 时间趋势 月度收入
饼图 部分到整体关系 市场份额
散点图 变量间关系 身高与体重
直方图 值分布 年龄分布
箱线图 统计分布 按部门薪资范围
热图 矩阵数据、相关性 特征相关性
面积图 累积趋势 堆叠收入流
气泡图 三维数据 销售额 vs 利润 vs 市场份额
树状图 分层数据 磁盘空间使用情况

Python - Matplotlib

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

def create_bar_chart(data, x_col, y_col, title='条形图', output='chart.png'):
    """
    创建条形图
    """
    plt.figure(figsize=(10, 6))

    if isinstance(data, pd.DataFrame):
        x = data[x_col]
        y = data[y_col]
    else:
        x = data['labels']
        y = data['values']

    bars = plt.bar(x, y, color='steelblue', alpha=0.8)

    # 在条形上添加值标签
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width()/2., height,
                f'{height:.1f}',
                ha='center', va='bottom')

    plt.title(title, fontsize=16, fontweight='bold')
    plt.xlabel(x_col if isinstance(data, pd.DataFrame) else '类别', fontsize=12)
    plt.ylabel(y_col if isinstance(data, pd.DataFrame) else '值', fontsize=12)
    plt.xticks(rotation=45, ha='right')
    plt.grid(axis='y', alpha=0.3)
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_line_chart(data, x_col, y_col, title='折线图', output='chart.png'):
    """
    创建折线图
    """
    plt.figure(figsize=(12, 6))

    if isinstance(data, pd.DataFrame):
        x = data[x_col]
        y = data[y_col]
    else:
        x = data['x']
        y = data['y']

    plt.plot(x, y, marker='o', linewidth=2, markersize=6, color='steelblue')

    # 添加网格
    plt.grid(True, alpha=0.3)

    plt.title(title, fontsize=16, fontweight='bold')
    plt.xlabel(x_col if isinstance(data, pd.DataFrame) else 'X', fontsize=12)
    plt.ylabel(y_col if isinstance(data, pd.DataFrame) else 'Y', fontsize=12)
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_pie_chart(data, labels_col, values_col, title='饼图', output='chart.png'):
    """
    创建饼图
    """
    plt.figure(figsize=(10, 8))

    if isinstance(data, pd.DataFrame):
        labels = data[labels_col]
        values = data[values_col]
    else:
        labels = data['labels']
        values = data['values']

    # 创建颜色调色板
    colors = plt.cm.Set3(np.linspace(0, 1, len(labels)))

    # 创建饼图
    wedges, texts, autotexts = plt.pie(
        values,
        labels=labels,
        autopct='%1.1f%%',
        startangle=90,
        colors=colors,
        explode=[0.05] * len(labels)  # 稍微分离切片
    )

    # 样式化百分比文本
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontweight('bold')
        autotext.set_fontsize(10)

    plt.title(title, fontsize=16, fontweight='bold')
    plt.axis('equal')
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_scatter_plot(data, x_col, y_col, color_col=None, size_col=None,
                       title='散点图', output='chart.png'):
    """
    创建散点图
    """
    plt.figure(figsize=(10, 8))

    if isinstance(data, pd.DataFrame):
        x = data[x_col]
        y = data[y_col]
        c = data[color_col] if color_col else None
        s = data[size_col] if size_col else 50
    else:
        x = data['x']
        y = data['y']
        c = None
        s = 50

    scatter = plt.scatter(x, y, c=c, s=s, alpha=0.6, cmap='viridis')

    if color_col:
        plt.colorbar(scatter, label=color_col)

    # 添加趋势线
    z = np.polyfit(x, y, 1)
    p = np.poly1d(z)
    plt.plot(x, p(x), "r--", alpha=0.8, label='趋势')

    plt.title(title, fontsize=16, fontweight='bold')
    plt.xlabel(x_col if isinstance(data, pd.DataFrame) else 'X', fontsize=12)
    plt.ylabel(y_col if isinstance(data, pd.DataFrame) else 'Y', fontsize=12)
    plt.grid(True, alpha=0.3)
    plt.legend()
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_histogram(data, column, bins=30, title='直方图', output='chart.png'):
    """
    创建直方图
    """
    plt.figure(figsize=(10, 6))

    if isinstance(data, pd.DataFrame):
        values = data[column]
    else:
        values = data

    n, bins, patches = plt.hist(values, bins=bins, color='steelblue',
                                 alpha=0.7, edgecolor='black')

    # 添加均值线
    mean_val = np.mean(values)
    plt.axvline(mean_val, color='red', linestyle='dashed', linewidth=2,
                label=f'均值: {mean_val:.2f}')

    # 添加中位数线
    median_val = np.median(values)
    plt.axvline(median_val, color='green', linestyle='dashed', linewidth=2,
                label=f'中位数: {median_val:.2f}')

    plt.title(title, fontsize=16, fontweight='bold')
    plt.xlabel(column if isinstance(data, pd.DataFrame) else '值', fontsize=12)
    plt.ylabel('频率', fontsize=12)
    plt.legend()
    plt.grid(axis='y', alpha=0.3)
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_box_plot(data, columns, title='箱线图', output='chart.png'):
    """
    创建箱线图
    """
    plt.figure(figsize=(10, 6))

    if isinstance(data, pd.DataFrame):
        data_to_plot = [data[col].dropna() for col in columns]
        labels = columns
    else:
        data_to_plot = data
        labels = [f'组 {i+1}' for i in range(len(data))]

    bp = plt.boxplot(data_to_plot, labels=labels, patch_artist=True)

    # 颜色化箱子
    for patch in bp['boxes']:
        patch.set_facecolor('lightblue')
        patch.set_alpha(0.7)

    plt.title(title, fontsize=16, fontweight='bold')
    plt.ylabel('值', fontsize=12)
    plt.grid(axis='y', alpha=0.3)
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

def create_heatmap(data, title='热图', output='chart.png'):
    """
    创建热图(相关矩阵)
    """
    plt.figure(figsize=(10, 8))

    if isinstance(data, pd.DataFrame):
        # 计算相关矩阵
        corr_matrix = data.corr()
    else:
        corr_matrix = data

    # 创建热图
    im = plt.imshow(corr_matrix, cmap='coolwarm', aspect='auto',
                    vmin=-1, vmax=1)

    # 添加颜色条
    cbar = plt.colorbar(im)
    cbar.set_label('相关性', rotation=270, labelpad=20)

    # 设置刻度和标签
    plt.xticks(range(len(corr_matrix.columns)), corr_matrix.columns,
               rotation=45, ha='right')
    plt.yticks(range(len(corr_matrix.columns)), corr_matrix.columns)

    # 添加相关值
    for i in range(len(corr_matrix)):
        for j in range(len(corr_matrix.columns)):
            text = plt.text(j, i, f'{corr_matrix.iloc[i, j]:.2f}',
                          ha='center', va='center', color='black', fontsize=9)

    plt.title(title, fontsize=16, fontweight='bold', pad=20)
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

Python - Seaborn

import seaborn as sns

def create_seaborn_chart(data, chart_type, x, y=None, hue=None,
                        title='图表', output='chart.png'):
    """
    使用Seaborn创建图表
    """
    plt.figure(figsize=(12, 6))

    # 设置样式
    sns.set_style("whitegrid")
    sns.set_palette("husl")

    if chart_type == 'bar':
        sns.barplot(data=data, x=x, y=y, hue=hue)

    elif chart_type == 'line':
        sns.lineplot(data=data, x=x, y=y, hue=hue, marker='o')

    elif chart_type == 'scatter':
        sns.scatterplot(data=data, x=x, y=y, hue=hue, size=hue, alpha=0.6)

    elif chart_type == 'box':
        sns.boxplot(data=data, x=x, y=y, hue=hue)

    elif chart_type == 'violin':
        sns.violinplot(data=data, x=x, y=y, hue=hue)

    elif chart_type == 'dist':
        sns.histplot(data=data, x=x, hue=hue, kde=True)

    elif chart_type == 'heatmap':
        sns.heatmap(data.corr(), annot=True, fmt='.2f', cmap='coolwarm',
                   center=0, square=True, linewidths=1)

    elif chart_type == 'pairplot':
        # 特殊情况 - 创建自己的图形
        g = sns.pairplot(data, hue=hue)
        g.savefig(output, dpi=300, bbox_inches='tight')
        return output

    plt.title(title, fontsize=16, fontweight='bold')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

# 高级Seaborn可视化
def create_facet_grid(data, x, y, col=None, row=None, hue=None,
                     title='分面网格', output='chart.png'):
    """
    创建分面图表
    """
    g = sns.FacetGrid(data, col=col, row=row, hue=hue, height=4)
    g.map(sns.scatterplot, x, y, alpha=0.6)
    g.add_legend()
    g.fig.suptitle(title, y=1.02, fontsize=16, fontweight='bold')

    plt.savefig(output, dpi=300, bbox_inches='tight')
    plt.close()

    return output

JavaScript - Chart.js

const { ChartJSNodeCanvas } = require('chartjs-node-canvas');

async function createBarChart(data, options = {}) {
  const width = options.width || 800;
  const height = options.height || 600;

  const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });

  const configuration = {
    type: 'bar',
    data: {
      labels: data.labels,
      datasets: [{
        label: options.label || '数据集',
        data: data.values,
        backgroundColor: 'rgba(54, 162, 235, 0.6)',
        borderColor: 'rgba(54, 162, 235, 1)',
        borderWidth: 2
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: options.title || '条形图',
          font: { size: 18 }
        },
        legend: {
          display: true,
          position: 'top'
        }
      },
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  };

  const imageBuffer = await chartJSNodeCanvas.renderToBuffer(configuration);
  return imageBuffer;
}

async function createLineChart(data, options = {}) {
  const width = options.width || 800;
  const height = options.height || 600;

  const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });

  const configuration = {
    type: 'line',
    data: {
      labels: data.labels,
      datasets: [{
        label: options.label || '数据集',
        data: data.values,
        borderColor: 'rgba(75, 192, 192, 1)',
        backgroundColor: 'rgba(75, 192, 192, 0.2)',
        borderWidth: 2,
        tension: 0.4
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: options.title || '折线图',
          font: { size: 18 }
        }
      },
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  };

  const imageBuffer = await chartJSNodeCanvas.renderToBuffer(configuration);
  return imageBuffer;
}

async function createPieChart(data, options = {}) {
  const width = options.width || 800;
  const height = options.height || 600;

  const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });

  const configuration = {
    type: 'pie',
    data: {
      labels: data.labels,
      datasets: [{
        data: data.values,
        backgroundColor: [
          'rgba(255, 99, 132, 0.6)',
          'rgba(54, 162, 235, 0.6)',
          'rgba(255, 206, 86, 0.6)',
          'rgba(75, 192, 192, 0.6)',
          'rgba(153, 102, 255, 0.6)',
          'rgba(255, 159, 64, 0.6)'
        ],
        borderWidth: 2
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: options.title || '饼图',
          font: { size: 18 }
        },
        legend: {
          position: 'right'
        }
      }
    }
  };

  const imageBuffer = await chartJSNodeCanvas.renderToBuffer(configuration);
  return imageBuffer;
}

交互式图表 - Plotly

import plotly.express as px
import plotly.graph_objects as go

def create_interactive_bar(data, x, y, title='条形图', output='chart.html'):
    """
    使用Plotly创建交互式条形图
    """
    fig = px.bar(data, x=x, y=y, title=title,
                 color=y, color_continuous_scale='Viridis')

    fig.update_layout(
        font=dict(size=14),
        showlegend=True,
        hovermode='x unified'
    )

    fig.write_html(output)
    return output

def create_interactive_line(data, x, y, title='折线图', output='chart.html'):
    """
    创建交互式折线图
    """
    fig = px.line(data, x=x, y=y, title=title, markers=True)

    fig.update_traces(line=dict(width=3))

    fig.update_layout(
        hovermode='x unified',
        font=dict(size=14)
    )

    fig.write_html(output)
    return output

def create_interactive_scatter(data, x, y, color=None, size=None,
                              title='散点图', output='chart.html'):
    """
    创建交互式散点图
    """
    fig = px.scatter(data, x=x, y=y, color=color, size=size,
                    title=title, hover_data=data.columns)

    fig.update_traces(marker=dict(line=dict(width=0.5, color='white')))

    fig.write_html(output)
    return output

def create_3d_scatter(data, x, y, z, color=None, title='3D散点图',
                     output='chart.html'):
    """
    创建3D散点图
    """
    fig = px.scatter_3d(data, x=x, y=y, z=z, color=color, title=title)

    fig.update_layout(scene=dict(
        xaxis_title=x,
        yaxis_title=y,
        zaxis_title=z
    ))

    fig.write_html(output)
    return output

def create_time_series(data, date_col, value_col, title='时间序列',
                      output='chart.html'):
    """
    创建时间序列图表
    """
    fig = go.Figure()

    fig.add_trace(go.Scatter(
        x=data[date_col],
        y=data[value_col],
        mode='lines+markers',
        name=value_col,
        line=dict(width=2),
        marker=dict(size=6)
    ))

    # 添加范围滑块
    fig.update_xaxes(
        rangeslider_visible=True,
        rangeselector=dict(
            buttons=list([
                dict(count=7, label="1周", step="day", stepmode="backward"),
                dict(count=1, label="1月", step="month", stepmode="backward"),
                dict(count=3, label="3月", step="month", stepmode="backward"),
                dict(count=1, label="1年", step="year", stepmode="backward"),
                dict(step="all")
            ])
        )
    )

    fig.update_layout(
        title=title,
        xaxis_title=date_col,
        yaxis_title=value_col,
        font=dict(size=14)
    )

    fig.write_html(output)
    return output

def create_dashboard(data, output='dashboard.html'):
    """
    创建多图表仪表板
    """
    from plotly.subplots import make_subplots

    fig = make_subplots(
        rows=2, cols=2,
        subplot_titles=('条形图', '折线图', '饼图', '散点图'),
        specs=[[{'type': 'bar'}, {'type': 'scatter'}],
               [{'type': 'pie'}, {'type': 'scatter'}]]
    )

    # 添加图表
    # 条形图
    fig.add_trace(
        go.Bar(x=data['category'], y=data['value1'], name='条形图'),
        row=1, col=1
    )

    # 折线图
    fig.add_trace(
        go.Scatter(x=data['date'], y=data['value2'], mode='lines', name='折线图'),
        row=1, col=2
    )

    # 饼图
    fig.add_trace(
        go.Pie(labels=data['category'], values=data['value1'], name='饼图'),
        row=2, col=1
    )

    # 散点图
    fig.add_trace(
        go.Scatter(x=data['value1'], y=data['value2'], mode='markers', name='散点图'),
        row=2, col=2
    )

    fig.update_layout(height=800, showlegend=True, title_text="仪表板")

    fig.write_html(output)
    return output

图表样式和主题

# Matplotlib主题
def apply_matplotlib_theme(theme='default'):
    """
    将主题应用于matplotlib图表
    """
    themes = {
        'default': 'seaborn-v0_8-darkgrid',
        'minimal': 'seaborn-v0_8-whitegrid',
        'dark': 'dark_background',
        'classic': 'classic',
        'ggplot': 'ggplot'
    }

    plt.style.use(themes.get(theme, 'default'))

# 自定义调色板
COLOR_PALETTES = {
    'corporate': ['#003f5c', '#58508d', '#bc5090', '#ff6361', '#ffa600'],
    'pastel': ['#a8e6cf', '#dcedc1', '#ffd3b6', '#ffaaa5', '#ff8b94'],
    'vibrant': ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6'],
    'monochrome': ['#2c3e50', '#34495e', '#7f8c8d', '#95a5a6', '#bdc3c7']
}

def apply_color_palette(palette_name='corporate'):
    """应用自定义调色板"""
    colors = COLOR_PALETTES.get(palette_name, COLOR_PALETTES['corporate'])
    plt.rcParams['axes.prop_cycle'] = plt.cycler(color=colors)

导出格式

def export_chart_multiple_formats(fig, base_name='chart'):
    """
    以多种格式导出图表
    """
    formats = {
        'png': {'dpi': 300, 'transparent': False},
        'svg': {'format': 'svg'},
        'pdf': {'format': 'pdf'},
        'jpg': {'dpi': 300, 'format': 'jpg'}
    }

    files = []

    for fmt, kwargs in formats.items():
        output_file = f"{base_name}.{fmt}"
        fig.savefig(output_file, bbox_inches='tight', **kwargs)
        files.append(output_file)

    return files

图表生成流程

def generate_charts_from_data(data, chart_configs, output_dir='charts'):
    """
    基于配置从数据生成多个图表

    chart_configs = [
        {
            'type': 'bar',
            'x': 'category',
            'y': 'value',
            'title': '按类别销售额',
            'output': 'sales_bar.png'
        },
        ...
    ]
    """
    import os
    os.makedirs(output_dir, exist_ok=True)

    generated_charts = []

    for config in chart_configs:
        chart_type = config['type']
        output = os.path.join(output_dir, config['output'])

        if chart_type == 'bar':
            create_bar_chart(data, config['x'], config['y'],
                           config.get('title', '图表'), output)

        elif chart_type == 'line':
            create_line_chart(data, config['x'], config['y'],
                            config.get('title', '图表'), output)

        elif chart_type == 'pie':
            create_pie_chart(data, config['x'], config['y'],
                           config.get('title', '图表'), output)

        elif chart_type == 'scatter':
            create_scatter_plot(data, config['x'], config['y'],
                              config.get('color'), config.get('size'),
                              config.get('title', '图表'), output)

        elif chart_type == 'heatmap':
            create_heatmap(data, config.get('title', '图表'), output)

        generated_charts.append({
            'type': chart_type,
            'title': config.get('title'),
            'file': output
        })

    return generated_charts

最佳实践

  1. 选择适当的图表类型 用于数据
  2. 使用清晰、描述性的标题 和标签
  3. 应用一致的配色方案 跨图表
  4. 确保可读性(字体大小、对比度)
  5. 添加上下文(注释、参考线)
  6. 以高分辨率导出(最小300 DPI)
  7. 考虑可访问性(色盲友好调色板)
  8. 在不同屏幕尺寸上测试(响应式设计)
  9. 优化文件大小 用于网络使用
  10. 文档化图表生成 代码以确保可重现性

常见图表模式

比较图表

  • 条形图用于类别比较
  • 分组条形图用于多系列比较
  • 堆叠条形图用于部分到整体比较

趋势图表

  • 折线图用于时间序列
  • 面积图用于累积趋势
  • 迷你图用于内联趋势

分布图表

  • 直方图用于频率分布
  • 箱线图用于统计分布
  • 小提琴图用于分布形状

关系图表

  • 散点图用于相关性
  • 气泡图用于3D关系
  • 热图用于矩阵关系

构成图表

  • 饼图用于简单的部分到整体
  • 堆叠面积图用于时间趋势
  • 树状图用于分层构成

注释

  • 始终标注轴并提供单位
  • 使用适当的比例(线性、对数)
  • 考虑数据墨水比率(最小化图表垃圾)
  • 使用不同的数据范围测试图表
  • 在使用多个系列时提供图例
  • 使用注释来突出关键洞察
  • 为出版物导出矢量格式图表
  • 保持配色方案在相关图表中一致
  • 考虑颜色含义的文化差异
  • 在可视化之前验证数据