0Pricing
AI Agents · 课时

自动生成图表与可视化内容

生成 matplotlib/seaborn 图表,并返回 Base64 图像结果。

自动生成图表与可视化内容 是 CoddyKit 上的免费 AI Agents 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。

代理为何生成图表

文本中的数字很难理解。一张展示 12 个月销售趋势的图表,可以在几秒钟内传达一段数字描述无法清晰表达的信息。

能够生成可视化内容的数据分析代理会实用得多——它能产生人类分析师同样的结果:既有数字,也有图表。

设置非交互式 Matplotlib

默认情况下,matplotlib 会打开 GUI 窗口。在代理中(代理运行在没有显示设备的服务器端),必须切换到 Agg 后端——它只渲染到文件,不使用 GUI。

请在导入 pyplot 之前进行设置,以避免显示错误。

import matplotlib
matplotlib.use('Agg')  # must be set BEFORE importing pyplot
import matplotlib.pyplot as plt
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

# Verify no display is needed
print('Backend:', matplotlib.get_backend())  # Should print: Agg

生成条形图

条形图用于比较不同类别的数值。它适用于前 N 名排名、类别比较以及前后对比。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

def create_bar_chart(labels, values, title, xlabel, ylabel, filename):
    fig, ax = plt.subplots(figsize=(10, 6))
    bars = ax.bar(labels, values, color='steelblue', edgecolor='white')

    # Add value labels on bars
    for bar, value in zip(bars, values):
        ax.text(
            bar.get_x() + bar.get_width() / 2,
            bar.get_height() + max(values) * 0.01,
            f'{value:,.0f}', ha='center', va='bottom', fontsize=9
        )

    ax.set_title(title, fontsize=14, pad=15)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    path = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(path, dpi=150, bbox_inches='tight')
    plt.close()
    return path

生成折线图

折线图用于展示随时间变化的趋势。它适用于时间序列数据,例如每日销售额、数月的用户增长情况,以及各个迭代周期的性能指标。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

def create_line_chart(x_values, y_values, title, xlabel, ylabel, filename, label=None):
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(x_values, y_values, marker='o', linewidth=2, markersize=5,
            color='darkorange', label=label or ylabel)

    # Highlight min and max points
    max_idx = y_values.index(max(y_values))
    min_idx = y_values.index(min(y_values))
    ax.annotate(f'Max: {max(y_values):,.0f}',
                xy=(x_values[max_idx], y_values[max_idx]),
                xytext=(5, 10), textcoords='offset points', color='green')

    ax.set_title(title, fontsize=14, pad=15)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.grid(True, alpha=0.3)
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    path = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(path, dpi=150, bbox_inches='tight')
    plt.close()
    return path

生成散点图

散点图可以揭示两个数值变量之间的关系,例如广告支出与收入之间的相关性,或订单规模与配送时间之间的关系。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

def create_scatter_chart(x_values, y_values, title, xlabel, ylabel, filename, add_trendline=True):
    fig, ax = plt.subplots(figsize=(8, 6))
    ax.scatter(x_values, y_values, alpha=0.6, color='royalblue', edgecolors='white', s=60)

    if add_trendline and len(x_values) > 2:
        z = np.polyfit(x_values, y_values, 1)
        p = np.poly1d(z)
        x_line = sorted(x_values)
        ax.plot(x_line, p(x_line), 'r--', alpha=0.7, label='Trend')
        ax.legend()

    # Compute and show correlation
    corr = np.corrcoef(x_values, y_values)[0, 1]
    ax.text(0.05, 0.95, f'r = {corr:.2f}', transform=ax.transAxes,
            fontsize=10, verticalalignment='top')

    ax.set_title(title, fontsize=14, pad=15)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    plt.tight_layout()

    path = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(path, dpi=150, bbox_inches='tight')
    plt.close()
    return path

生成直方图

直方图用于展示单个数值变量的分布,例如订单金额的分布、客户年龄分布或响应时间分布。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

def create_histogram(values, title, xlabel, filename, bins=20):
    fig, ax = plt.subplots(figsize=(8, 5))
    n, bin_edges, patches = ax.hist(values, bins=bins, color='mediumseagreen',
                                     edgecolor='white', alpha=0.8)

    # Add mean and median lines
    mean_val = np.mean(values)
    median_val = np.median(values)
    ax.axvline(mean_val, color='red', linestyle='--', label=f'Mean: {mean_val:.1f}')
    ax.axvline(median_val, color='blue', linestyle='--', label=f'Median: {median_val:.1f}')

    ax.set_title(title, fontsize=14, pad=15)
    ax.set_xlabel(xlabel)
    ax.set_ylabel('Frequency')
    ax.legend()
    plt.tight_layout()

    path = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(path, dpi=150, bbox_inches='tight')
    plt.close()
    return path

对代理响应进行 Base64 编码

将图表保存为 PNG 文件后,请将其编码为 base64,使其能够作为工具结果中的 JSON 可序列化字符串返回。调用方随后便可以渲染或显示该图表。

import base64

def file_to_base64(filepath):
    with open(filepath, 'rb') as f:
        return base64.b64encode(f.read()).decode('utf-8')

def create_chart_result(chart_path, chart_type, caption):
    b64 = file_to_base64(chart_path)
    return {
        'type': 'image',
        'chart_type': chart_type,
        'format': 'png',
        'base64': b64,
        'caption': caption,
        'file_path': chart_path
    }

# Usage after creating a chart
path = create_bar_chart(['Q1', 'Q2', 'Q3', 'Q4'], [12000, 15000, 18000, 22000],
                        'Quarterly Revenue', 'Quarter', 'Revenue ($)', 'revenue.png')
result = create_chart_result(path, 'bar', 'Quarterly revenue showing consistent growth')
print(f'Chart encoded: {len(result["base64"])} chars')

生成图表说明

没有说明文字的图表会迫使查看者自行解读。请让 LLM 生成一句话的说明,描述图表中可见的关键洞见。

def generate_chart_caption(chart_type, data_summary, question):
    prompt = f'''A {chart_type} chart was generated to answer: "{question}"

Data summary:
{data_summary}

Write a single clear sentence describing the most important insight shown in the chart.
Focus on the key finding, not on describing what type of chart it is.

Caption:'''
    caption = llm_call(prompt).strip()
    # Ensure it ends with a period
    if caption and not caption.endswith('.'):
        caption += '.'
    return caption

# Example
caption = generate_chart_caption(
    chart_type='bar',
    data_summary='Q1: $12k, Q2: $15k, Q3: $18k, Q4: $22k (83% total growth)',
    question='How did quarterly revenue trend this year?'
)
print(caption)
# -> "Revenue grew consistently each quarter, with Q4 nearly doubling Q1 figures."

自动选择图表类型

不同的问题需要不同的图表类型。与其将图表类型硬编码,不如让 LLM 根据数据特征和问题类型自行决定。

import json

CHART_TYPE_PROMPT = '''Choose the best chart type to answer this question.

Question: {question}
Data has columns: {columns}
Data sample: {sample}

Available chart types:
- bar: comparing values across categories
- line: trends over time
- scatter: relationship between two numeric variables
- histogram: distribution of one numeric variable
- pie: composition/proportions (use sparingly)

Return JSON: {{"chart_type": "bar", "x": "category_column", "y": "value_column",
              "title": "Chart title", "xlabel": "X label", "ylabel": "Y label"}}'''

def select_chart_type(question, df):
    sample = df.head(3).to_dict(orient='records')
    response = llm_call(CHART_TYPE_PROMPT.format(
        question=question,
        columns=list(df.columns),
        sample=json.dumps(sample, default=str)
    ))
    return json.loads(response)

统一的图表生成工具

将所有图表类型封装到一个代理可以调用的工具中。如果未指定图表类型,该工具会自动选择类型、创建图表、对其进行编码,并生成说明。

import pandas as pd

def generate_chart(df_name, question, chart_type=None, filename=None):
    df = dataframes.get(df_name)
    if df is None:
        return {'error': f'{df_name!r} not found'}

    # Auto-select chart type if not specified
    if not chart_type:
        spec = select_chart_type(question, df)
    else:
        spec = {'chart_type': chart_type}

    ct = spec.get('chart_type', 'bar')
    x_col = spec.get('x', df.columns[0])
    y_col = spec.get('y', df.select_dtypes(include='number').columns[0])
    title = spec.get('title', question[:60])
    fname = filename or f'chart_{ct}.png'

    x_vals = df[x_col].tolist()
    y_vals = df[y_col].tolist()

    if ct == 'bar':
        path = create_bar_chart(x_vals, y_vals, title, x_col, y_col, fname)
    elif ct == 'line':
        path = create_line_chart(x_vals, y_vals, title, x_col, y_col, fname)
    elif ct == 'histogram':
        path = create_histogram(y_vals, title, y_col, fname)
    else:
        path = create_scatter_chart(x_vals, y_vals, title, x_col, y_col, fname)

    caption = generate_chart_caption(ct, f'{x_col} vs {y_col}', question)
    return create_chart_result(path, ct, caption)

多系列和分组图表

比较多个组时(例如比较各地区随时间变化的收入),请使用分组图表或多系列图表。Matplotlib 支持在同一幅图中绘制多条线,也支持带偏移量的分组条形图。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import os

OUTPUT_DIR = '/tmp/agent_charts'
os.makedirs(OUTPUT_DIR, exist_ok=True)

def create_grouped_bar_chart(categories, series_data, title, xlabel, ylabel, filename):
    n_groups = len(categories)
    n_series = len(series_data)
    bar_width = 0.8 / n_series
    x = np.arange(n_groups)

    fig, ax = plt.subplots(figsize=(12, 6))
    colors = ['steelblue', 'darkorange', 'forestgreen', 'crimson']

    for i, (label, values) in enumerate(series_data.items()):
        offset = (i - (n_series - 1) / 2) * bar_width
        ax.bar(x + offset, values, bar_width, label=label,
               color=colors[i % len(colors)], alpha=0.85)

    ax.set_xticks(x)
    ax.set_xticklabels(categories, rotation=30, ha='right')
    ax.set_title(title, fontsize=14, pad=15)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.legend()
    plt.tight_layout()

    path = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(path, dpi=150, bbox_inches='tight')
    plt.close()
    return path

知识检查

为什么必须在服务器端代理导入 pyplot 之前设置 matplotlib 的 Agg 后端?

回顾:自动生成图表和可视化内容

数据代理生成图表的步骤包括:设置 matplotlib Agg 后端(不使用 GUI)、使用 plt.savefig() 创建图表、进行 base64 编码以便通过 JSON 传输,以及生成由 LLM 编写的说明来突出关键洞见。

四种基本图表类型:bar(类别比较)、折线(时间序列)、scatter(带趋势线的相关性)、直方图(分布)。自动选择图表类型后,LLM 可以根据数据特征和用户问题选择最合适的可视化方式。

常见问题解答

「自动生成图表与可视化内容」课时是免费的吗?

是的 — 「自动生成图表与可视化内容」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。

「自动生成图表与可视化内容」这节课中我会学到什么?

生成 matplotlib/seaborn 图表,并返回 Base64 图像结果。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Agents 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「自动生成图表与可视化内容」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Agents 课中编写并运行代码吗?

能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 用于数据分析的代码解释器模式
  2. 由 Pandas 驱动的数据代理工具
  3. 自动生成图表与可视化内容
  4. 统计摘要代理
← 返回 AI Agents