a
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
"""
|
||||
高级图片生成技能 - 整合多个库
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
import qrcode
|
||||
from wordcloud import WordCloud
|
||||
import ascii_magic
|
||||
|
||||
class AdvancedImageSkill:
|
||||
"""高级图片生成技能"""
|
||||
|
||||
def __init__(self):
|
||||
plt.switch_backend('Agg')
|
||||
sns.set_style("whitegrid")
|
||||
self.default_font = ImageFont.load_default()
|
||||
print("Advanced Image Skill initialized")
|
||||
|
||||
def create_advanced_chart(self, data, chart_type='bar', title='', style='seaborn'):
|
||||
"""创建高级图表
|
||||
|
||||
Args:
|
||||
data: 数据字典
|
||||
chart_type: 图表类型 ('bar', 'line', 'scatter', 'heatmap', 'pie')
|
||||
title: 图表标题
|
||||
style: 样式 ('seaborn', 'matplotlib')
|
||||
|
||||
Returns:
|
||||
图片路径
|
||||
"""
|
||||
try:
|
||||
plt.figure(figsize=(10, 6))
|
||||
|
||||
if style == 'seaborn':
|
||||
sns.set_palette("husl")
|
||||
|
||||
labels = data.get('labels', [])
|
||||
values = data.get('values', [])
|
||||
|
||||
if chart_type == 'bar':
|
||||
if style == 'seaborn':
|
||||
ax = sns.barplot(x=labels, y=values)
|
||||
# 添加数值标签
|
||||
for i, v in enumerate(values):
|
||||
ax.text(i, v + 0.1, str(v), ha='center')
|
||||
else:
|
||||
bars = plt.bar(labels, values)
|
||||
for bar in bars:
|
||||
height = bar.get_height()
|
||||
plt.text(bar.get_x() + bar.get_width()/2., height + 0.1,
|
||||
f'{height}', ha='center', va='bottom')
|
||||
|
||||
elif chart_type == 'line':
|
||||
if style == 'seaborn':
|
||||
sns.lineplot(x=labels, y=values, marker='o', linewidth=2)
|
||||
else:
|
||||
plt.plot(labels, values, marker='o', linewidth=2)
|
||||
|
||||
elif chart_type == 'scatter' and 'x' in data and 'y' in data:
|
||||
if style == 'seaborn':
|
||||
sns.scatterplot(x=data['x'], y=data['y'])
|
||||
else:
|
||||
plt.scatter(data['x'], data['y'])
|
||||
|
||||
elif chart_type == 'heatmap' and 'matrix' in data:
|
||||
if style == 'seaborn':
|
||||
sns.heatmap(data['matrix'], annot=True, fmt='.1f', cmap='YlOrRd')
|
||||
else:
|
||||
plt.imshow(data['matrix'], cmap='hot', interpolation='nearest')
|
||||
plt.colorbar()
|
||||
|
||||
elif chart_type == 'pie':
|
||||
plt.pie(values, labels=labels, autopct='%1.1f%%', startangle=90)
|
||||
plt.axis('equal') # 确保饼图是圆形
|
||||
|
||||
if title:
|
||||
plt.title(title, fontsize=14, fontweight='bold')
|
||||
|
||||
plt.tight_layout()
|
||||
path = tempfile.mktemp(suffix='.png')
|
||||
plt.savefig(path, dpi=120, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
return path
|
||||
|
||||
except Exception as e:
|
||||
plt.close()
|
||||
raise Exception(f'高级图表生成失败: {e}')
|
||||
|
||||
def create_wordcloud(self, text, width=800, height=400,
|
||||
background_color='white', colormap='viridis'):
|
||||
"""创建词云图
|
||||
|
||||
Args:
|
||||
text: 文本内容
|
||||
width: 图片宽度
|
||||
height: 图片高度
|
||||
background_color: 背景颜色
|
||||
colormap: 颜色映射
|
||||
|
||||
Returns:
|
||||
图片路径
|
||||
"""
|
||||
try:
|
||||
# 创建词云
|
||||
wordcloud = WordCloud(
|
||||
width=width,
|
||||
height=height,
|
||||
background_color=background_color,
|
||||
colormap=colormap,
|
||||
max_words=200,
|
||||
contour_width=1,
|
||||
contour_color='steelblue'
|
||||
).generate(text)
|
||||
|
||||
# 保存图片
|
||||
path = tempfile.mktemp(suffix='.png')
|
||||
wordcloud.to_file(path)
|
||||
|
||||
return path
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f'词云图生成失败: {e}')
|
||||
|
||||
def create_ascii_art(self, image_path=None, text=None, columns=100):
|
||||
"""创建ASCII艺术
|
||||
|
||||
Args:
|
||||
image_path: 图片路径(将图片转为ASCII)
|
||||
text: 文本(创建文本ASCII艺术)
|
||||
columns: 列数
|
||||
|
||||
Returns:
|
||||
ASCII文本或图片路径
|
||||
"""
|
||||
try:
|
||||
if image_path and os.path.exists(image_path):
|
||||
# 从图片创建ASCII艺术
|
||||
output = ascii_magic.from_image(
|
||||
image_path,
|
||||
columns=columns,
|
||||
mode=ascii_magic.Modes.HTML
|
||||
)
|
||||
# 保存为HTML
|
||||
path = tempfile.mktemp(suffix='.html')
|
||||
ascii_magic.to_html_file(path, output)
|
||||
return path
|
||||
|
||||
elif text:
|
||||
# 从文本创建ASCII艺术
|
||||
# 这里简化处理,实际可以使用更复杂的ASCII艺术生成
|
||||
ascii_text = f"""
|
||||
╔{'═' * (columns-2)}╗
|
||||
║{' ' * (columns-2)}║
|
||||
║{text.center(columns-2)}║
|
||||
║{' ' * (columns-2)}║
|
||||
╚{'═' * (columns-2)}╝
|
||||
"""
|
||||
path = tempfile.mktemp(suffix='.txt')
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write(ascii_text)
|
||||
return path
|
||||
|
||||
else:
|
||||
raise Exception('需要提供图片路径或文本')
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f'ASCII艺术生成失败: {e}')
|
||||
|
||||
def create_color_palette(self, colors, title='颜色调色板'):
|
||||
"""创建颜色调色板展示
|
||||
|
||||
Args:
|
||||
colors: 颜色列表,如 ['#FF5733', '#33FF57', '#3357FF']
|
||||
title: 标题
|
||||
|
||||
Returns:
|
||||
图片路径
|
||||
"""
|
||||
try:
|
||||
fig, axes = plt.subplots(1, len(colors), figsize=(len(colors)*2, 3))
|
||||
|
||||
if len(colors) == 1:
|
||||
axes = [axes]
|
||||
|
||||
for ax, color in zip(axes, colors):
|
||||
ax.add_patch(plt.Rectangle((0, 0), 1, 1, color=color))
|
||||
ax.text(0.5, -0.2, color, ha='center', transform=ax.transAxes)
|
||||
ax.set_xlim(0, 1)
|
||||
ax.set_ylim(0, 1)
|
||||
ax.axis('off')
|
||||
|
||||
plt.suptitle(title, fontsize=14, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
|
||||
path = tempfile.mktemp(suffix='.png')
|
||||
plt.savefig(path, dpi=100, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
return path
|
||||
|
||||
except Exception as e:
|
||||
plt.close()
|
||||
raise Exception(f'颜色调色板生成失败: {e}')
|
||||
|
||||
def create_data_card(self, title, data_dict, theme='light'):
|
||||
"""创建数据卡片
|
||||
|
||||
Args:
|
||||
title: 卡片标题
|
||||
data_dict: 数据字典
|
||||
theme: 主题 ('light', 'dark')
|
||||
|
||||
Returns:
|
||||
图片路径
|
||||
"""
|
||||
try:
|
||||
# 设置颜色主题
|
||||
if theme == 'dark':
|
||||
bg_color = '#2c3e50'
|
||||
text_color = '#ecf0f1'
|
||||
accent_color = '#3498db'
|
||||
else:
|
||||
bg_color = '#ffffff'
|
||||
text_color = '#2c3e50'
|
||||
accent_color = '#3498db'
|
||||
|
||||
# 计算卡片尺寸
|
||||
num_items = len(data_dict)
|
||||
card_width = 500
|
||||
card_height = 150 + num_items * 40
|
||||
|
||||
# 创建卡片
|
||||
img = Image.new('RGB', (card_width, card_height), color=bg_color)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# 标题区域
|
||||
draw.rectangle([0, 0, card_width, 60], fill=accent_color)
|
||||
draw.text((20, 20), title, fill='white' if theme == 'dark' else 'white')
|
||||
|
||||
# 数据项
|
||||
y = 80
|
||||
for key, value in data_dict.items():
|
||||
# 键
|
||||
draw.text((30, y), f'• {key}:', fill=text_color)
|
||||
|
||||
# 值(如果是数字,可以添加进度条)
|
||||
value_x = 200
|
||||
draw.text((value_x, y), str(value), fill=accent_color)
|
||||
|
||||
# 如果是百分比,添加进度条
|
||||
if isinstance(value, (int, float)) and 0 <= value <= 100:
|
||||
bar_width = 200
|
||||
bar_height = 20
|
||||
bar_x = 250
|
||||
|
||||
# 进度条背景
|
||||
draw.rectangle([bar_x, y, bar_x + bar_width, y + bar_height],
|
||||
fill='#ecf0f1' if theme == 'light' else '#34495e')
|
||||
|
||||
# 进度条前景
|
||||
fill_width = int(bar_width * value / 100)
|
||||
draw.rectangle([bar_x, y, bar_x + fill_width, y + bar_height],
|
||||
fill=accent_color)
|
||||
|
||||
# 百分比文本
|
||||
draw.text((bar_x + 5, y), f'{value}%',
|
||||
fill='white' if value > 50 else text_color)
|
||||
|
||||
y += 40
|
||||
|
||||
# 边框
|
||||
draw.rectangle([10, 70, card_width - 10, card_height - 10],
|
||||
outline=accent_color, width=2)
|
||||
|
||||
path = tempfile.mktemp(suffix='.png')
|
||||
img.save(path)
|
||||
|
||||
return path
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f'数据卡片生成失败: {e}')
|
||||
|
||||
def create_comparison_chart(self, data_sets, labels, chart_type='grouped_bar'):
|
||||
"""创建对比图表
|
||||
|
||||
Args:
|
||||
data_sets: 数据集列表,每个数据集是一个数值列表
|
||||
labels: 标签列表
|
||||
chart_type: 图表类型 ('grouped_bar', 'stacked_bar', 'line')
|
||||
|
||||
Returns:
|
||||
图片路径
|
||||
"""
|
||||
try:
|
||||
plt.figure(figsize=(12, 7))
|
||||
|
||||
x = np.arange(len(labels))
|
||||
width = 0.8 / len(data_sets)
|
||||
|
||||
if chart_type == 'grouped_bar':
|
||||
for i, data in enumerate(data_sets):
|
||||
offset = (i - len(data_sets)/2 + 0.5) * width
|
||||
bars = plt.bar(x + offset, data, width, label=f'数据集 {i+1}')
|
||||
|
||||
# 添加数值标签
|
||||
for bar in bars:
|
||||
height = bar.get_height()
|
||||
plt.text(bar.get_x() + bar.get_width()/2., height + 0.1,
|
||||
f'{height}', ha='center', va='bottom', fontsize=8)
|
||||
|
||||
elif chart_type == 'stacked_bar':
|
||||
bottom = np.zeros(len(labels))
|
||||
for i, data in enumerate(data_sets):
|
||||
plt.bar(x, data, width, bottom=bottom, label=f'数据集 {i+1}')
|
||||
bottom += data
|
||||
|
||||
elif chart_type == 'line':
|
||||
for i, data in enumerate(data_sets):
|
||||
plt.plot(x, data, marker='o', linewidth=2, label=f'数据集 {i+1}')
|
||||
|
||||
plt.xlabel('类别', fontsize=12)
|
||||
plt.ylabel('数值', fontsize=12)
|
||||
plt.title('数据对比分析', fontsize=14, fontweight='bold')
|
||||
plt.xticks(x, labels)
|
||||
plt.legend()
|
||||
plt.grid(True, alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
path = tempfile.mktemp(suffix='.png')
|
||||
plt.savefig(path, dpi=120, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
return path
|
||||
|
||||
except Exception as e:
|
||||
plt.close()
|
||||
raise Exception(f'对比图表生成失败: {e}')
|
||||
|
||||
# 创建技能实例
|
||||
advanced_skill = AdvancedImageSkill()
|
||||
|
||||
# 导出函数
|
||||
def create_advanced_chart(*args, **kwargs):
|
||||
return advanced_skill.create_advanced_chart(*args, **kwargs)
|
||||
|
||||
def create_wordcloud(*args, **kwargs):
|
||||
return advanced_skill.create_wordcloud(*args, **kwargs)
|
||||
|
||||
def create_ascii_art(*args, **kwargs):
|
||||
return advanced_skill.create_ascii_art(*args, **kwargs)
|
||||
|
||||
def create_color_palette(*args, **kwargs):
|
||||
return advanced_skill.create_color_palette(*args, **kwargs)
|
||||
|
||||
def create_data_card(*args, **kwargs):
|
||||
return advanced_skill.create_data_card(*args, **kwargs)
|
||||
|
||||
def create_comparison_chart(*args, **kwargs):
|
||||
return advanced_skill.create_comparison_chart(*args, **kwargs)
|
||||
|
||||
__all__ = [
|
||||
'AdvancedImageSkill',
|
||||
'advanced_skill',
|
||||
'create_advanced_chart',
|
||||
'create_wordcloud',
|
||||
'create_ascii_art',
|
||||
'create_color_palette',
|
||||
'create_data_card',
|
||||
'create_comparison_chart'
|
||||
]
|
||||
Reference in New Issue
Block a user