- name
- chart-generator
- description
- Data visualization chart generator. Use when user needs to create charts from data for reports, presentations, or documents. Supports bar, line, pie, scatter, radar charts with PNG/SVG output. 数据可视化、图表生成、数据报告。
- version
- 1.0.2
- license
- MIT-0
- metadata
- {"openclaw":{"emoji":"📊","requires":{"bins":"[Truncated]"}}}
- dependencies
- pip install matplotlib pandas openpyxl python-docx pillow
# Chart Generator
Professional data visualization chart generator for reports, presentations, and documents.
## Features
- 📊 **Multiple Chart Types**: Bar, line, pie, scatter, radar, area, stacked
- 📁 **Multiple Data Sources**: CSV, Excel, JSON, manual, web, document extraction
- 🎨 **Professional Styling**: Clean, publication-ready charts with custom options
- 📐 **Flexible Output**: PNG, SVG, PDF, Word, Excel, Markdown, HTML
- 🔗 **Embed Support**: Direct embedding into documents
- 🌍 **Multi-Language**: Chinese, English, Japanese, Korean (no encoding issues)
- ✅ **Cross-Platform**: Windows, macOS, Linux
## Supported Chart Types
| Type | Use Case | Best For |
|------|----------|----------|
| **Bar Chart** | Compare values | Sales, rankings |
| **Line Chart** | Show trends | Time series, growth |
| **Pie Chart** | Show proportions | Market share, composition |
| **Scatter Plot** | Show correlation | Data relationships |
| **Radar Chart** | Multi-dimension | Performance comparison |
| **Area Chart** | Cumulative values | Stacked data |
| **Stacked Bar** | Composition | Multi-category breakdown |
## Trigger Conditions
- "帮我画图" / "Create a chart"
- "生成柱状图" / "Generate bar chart"
- "数据可视化" / "Data visualization"
- "做一个趋势图" / "Make a trend chart"
- "图表分析" / "Chart analysis"
- "chart-generator"
---
## Step 1: Understand Requirements
```
请提供以下信息:
图表类型:(柱状图/折线图/饼图/散点图/雷达图)
数据来源:(手动输入/CSV/Excel/JSON)
数据内容:
标题:
X轴标签:
Y轴标签:
输出格式:(PNG/SVG)
颜色要求:(默认/自定义)
```
---
## Step 2: Generate Chart
### Python Script Template
```python
python3 << 'PYEOF'
import os
import matplotlib.pyplot as plt
import matplotlib
import pandas as pd
import numpy as np
from matplotlib import font_manager
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['Noto Sans SC', 'SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
class ChartGenerator:
def __init__(self):
self.fig = None
self.ax = None
def create_bar_chart(self, labels, values, title='',
xlabel='', ylabel='',
color='#3182ce', output_path=None):
"""Create bar chart"""
self.fig, self.ax = plt.subplots(figsize=(10, 6))
bars = self.ax.bar(labels, values, color=color, edgecolor='white', linewidth=0.5)
# Add value labels on bars
for bar in bars:
height = bar.get_height()
self.ax.text(bar.get_x() + bar.get_width()/2., height,
f'{height:,.0f}',
ha='center', va='bottom', fontsize=10)
self.ax.set_title(title, fontsize=16, fontweight='bold', pad=20)
self.ax.set_xlabel(xlabel, fontsize=12)
self.ax.set_ylabel(ylabel, fontsize=12)
# Clean styling
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
if output_path:
self.fig.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
return output_path
return self.fig
def create_line_chart(self, x_data, y_data_list, labels=None,
title='', xlabel='', ylabel='',
colors=None, output_path=None):
"""Create line chart"""
self.fig, self.ax = plt.subplots(figsize=(10, 6))
if colors is None:
colors = ['#3182ce', '#48bb78', '#ed8936', '#e53e3e', '#9f7aea']
for i, y_data in enumerate(y_data_list):
color = colors[i % len(colors)]
label = labels[i] if labels and i < len(labels) else f'Series {i+1}'
self.ax.plot(x_data, y_data, marker='o', linewidth=2,
color=color, label=label, markersize=6)
self.ax.set_title(title, fontsize=16, fontweight='bold', pad=20)
self.ax.set_xlabel(xlabel, fontsize=12)
self.ax.set_ylabel(ylabel, fontsize=12)
if labels:
self.ax.legend(loc='best', framealpha=0.9)
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.grid(alpha=0.3)
plt.tight_layout()
if output_path:
self.fig.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
return output_path
return self.fig
def create_pie_chart(self, labels, values, title='',
colors=None, output_path=None):
"""Create pie chart"""
self.fig, self.ax = plt.subplots(figsize=(8, 8))
if colors is None:
colors = ['#3182ce', '#48bb78', '#ed8936', '#e53e3e', '#9f7aea',
'#38b2ac', '#d69e2e', '#667eea']
wedges, texts, autotexts = self.ax.pie(
values, labels=labels, colors=colors[:len(values)],
autopct='%1.1f%%', startangle=90,
textprops={'fontsize': 11}
)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
self.ax.set_title(title, fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
if output_path:
self.fig.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
return output_path
return self.fig
def create_scatter_plot(self, x_data, y_data, title='',
xlabel='', ylabel='',
color='#3182ce', output_path=None):
"""Create scatter plot"""
self.fig, self.ax = plt.subplots(figsize=(10, 6))
self.ax.scatter(x_data, y_data, c=color, alpha=0.6, s=50)
# Add trend line
z = np.polyfit(x_data, y_data, 1)
p = np.poly1d(z)
self.ax.plot(x_data, p(x_data), '--', color='#e53e3e', alpha=0.8, label='Trend')
self.ax.set_title(title, fontsize=16, fontweight='bold', pad=20)
self.ax.set_xlabel(xlabel, fontsize=12)
self.ax.set_ylabel(ylabel, fontsize=12)
self.ax.legend()
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.grid(alpha=0.3)
plt.tight_layout()
if output_path:
self.fig.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
return output_path
return self.fig
def create_multi_bar_chart(self, labels, data_dict, title='',
xlabel='', ylabel='', output_path=None):
"""Create grouped bar chart"""
self.fig, self.ax = plt.subplots(figsize=(12, 6))
x = np.arange(len(labels))
width = 0.8 / len(data_dict)
colors = ['#3182ce', '#48bb78', '#ed8936', '#e53e3e', '#9f7aea']
for i, (name, values) in enumerate(data_dict.items()):
offset = (i - len(data_dict)/2 + 0.5) * width
bars = self.ax.bar(x + offset, values, width, label=name,
color=colors[i % len(colors)], edgecolor='white')
self.ax.set_title(title, fontsize=16, fontweight='bold', pad=20)
self.ax.set_xlabel(xlabel, fontsize=12)
self.ax.set_ylabel(ylabel, fontsize=12)
self.ax.set_xticks(x)
self.ax.set_xticklabels(labels)
self.ax.legend()
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
if output_path:
self.fig.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
return output_path
return self.fig
def load_from_csv(self, csv_path, x_col=None, y_cols=None):
"""Load data from CSV file"""
df = pd.read_csv(csv_path)
if x_col is None:
x_col = df.columns[0]
if y_cols is None:
y_cols = [col for col in df.columns if col != x_col]
return {
'x': df[x_col].tolist(),
'y': {col: df[col].tolist() for col in y_cols},
'df': df
}
def load_from_excel(self, excel_path, sheet_name=0, x_col=None, y_cols=None):
"""Load data from Excel file"""
df = pd.read_excel(excel_path, sheet_name=sheet_name)
if x_col is None:
x_col = df.columns[0]
if y_cols is None:
y_cols = [col for col in df.columns if col != x_col]
return {
'x': df[x_col].tolist(),
'y': {col: df[col].tolist() for col in y_cols},
'df': df
}
def load_from_json(self, json_path):
"""Load data from JSON file"""
import json
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
return data
def load_from_directory(self, dir_path, file_pattern='*.csv'):
"""Load and aggregate data from multiple files in directory"""
import glob
all_data = []
for file_path in glob.glob(os.path.join(dir_path, file_pattern)):
if file_path.endswith('.csv'):
df = pd.read_csv(file_path)
elif file_path.endswith('.xlsx'):
df = pd.read_excel(file_path)
else:
continue
df['source_file'] = os.path.basename(file_path)
all_data.append(df)
if all_data:
return pd.concat(all_data, ignore_index=True)
return pd.DataFrame()
def extract_data_from_text(self, text):
"""Extract numerical data from text content"""
import re
# Find patterns like "Sales: 100" or "销售额:100万"
patterns = [
r'(\w+)\s*[::]\s*(\d+(?:\.\d+)?)',
r'(\d+(?:\.\d+)?)\s*[::]\s*(\w+)',
]
data = {}
for pattern in patterns:
matches = re.findall(pattern, text)
for match in matches:
if len(match) == 2:
key, value = match
try:
data[key] = float(value)
except ValueError:
pass
return data
def save_to_png(self, output_path, dpi=150):
"""Save chart as PNG"""
if self.fig:
self.fig.savefig(output_path, dpi=dpi, bbox_inches='tight',
facecolor='white', edgecolor='none')
return output_path
def save_to_svg(self, output_path):
"""Save chart as SVG"""
if self.fig:
self.fig.savefig(output_path, format='svg', bbox_inches='tight',
facecolor='white', edgecolor='none')
return output_path
def save_to_pdf(self, output_path):
"""Save chart as PDF"""
GitHubで見る