""" 高级图片生成技能 - 整合多个库 """ 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' ]