python import matplotlib.pyplot as plt import pandas as pd import numpy as np from pptx import Presentation from pptx.util import Inches, Pt from pptx.enum.text import PP_ALIGN from matplotlib.font_manager import FontProperties import warnings warnings.filterwarnings('ignore')# 忽略字体缺失的警告 # ================= 1. 仅需修改此处:本月真实业务数据 ================= DATA = { # 核心指标 'revenue': 125.6,# 营收(万元) 'revenue_growth': 18.5,# 营收环比增长(%) 'users': 45.2,# 活跃用户(万人) 'users_growth': 12.3,# 用户环比增长(%) 'conversion_rate': 28.6,# 转化率(%) 'conversion_change': 3.2,# 转化率变化(百分点) 'retention_rate': 67.4,# 留存率(%) # 趋势数据 'monthly_revenue': [98.2, 102.5, 105.8, 108.3, 112.4, 118.7, 125.6], # 产品排名数据 'product_ranking': [ {'name': '产品A', 'revenue': 45.6}, {'name': '产品B', 'revenue': 38.2}, {'name': '产品C', 'revenue': 28.9}, {'name': '产品D', 'revenue': 12.9}, ], # 月度时间标签 'months': ['1月', '2月', '3月', '4月', '5月', '6月', '7月'], } def get_up_down_icon(growth): """返回上升/下降图标""" return '▲' if growth >= 0 else '▼' def get_up_down_color(growth): """返回上升/下降颜色""" return '#4caf50' if growth >= 0 else '#f44336' def add_textbox(slide, text, left, top, width, height, font_size=18, bold=False, color='#333333'): """在幻灯片上添加文本框""" textbox = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(height)) tf = textbox.text_frame tf.word_wrap = True p = tf.paragraphs[0] p.text = text p.font.size = Pt(font_size) p.font.bold = bold p.font.color.rgb = _hex_to_rgb(color) p.alignment = PP_ALIGN.CENTER return textbox def _hex_to_rgb(hex_color): """将十六进制颜色字符串转换为RGB值""" hex_color = hex_color.lstrip('#') return int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16) def save_chart_and_insert_to_ppt(plt, figure, slide, left=0.5, top=1.5, width=9, height=4, dpi=300, filename='temp_chart.png'): """将 matplotlib 图表保存为高清图片并插入 PPT 中""" figure.savefig(filename, dpi=dpi, bbox_inches='tight', facecolor='white') plt.close(figure) slide.shapes.add_picture(filename, Inches(left), Inches(top), width=Inches(width), height=Inches(height)) def create_dashboard(): """生成产品月报数据看板(PPT + 高清PNG)""" # ================= 2. 使用 matplotlib 生成各种图表 ================= def plot_line_chart(): """绘制营收趋势折线图""" fig, ax = plt.subplots(figsize=(10, 5)) months = DATA['months'] revenues = DATA['monthly_revenue'] ax.plot(months, revenues, marker='o', linewidth=2.5, markersize=6, color='#2196f3') ax.set_title('月度营收趋势', fontsize=14, fontweight='bold', pad=15) ax.set_xlabel('月份') ax.set_ylabel('营收(万元)') ax.grid(True, alpha=0.3) for i, (m, v) in enumerate(zip(months, revenues)): ax.annotate(f'{v}', (m, v), textcoords='offset points', xytext=(0, 10), ha='center', fontsize=9) plt.tight_layout() return fig def plot_bar_chart(): """绘制产品营收排行柱状图""" fig, ax = plt.subplots(figsize=(8, 5)) products = [p['name'] for p in DATA['product_ranking']] revenues = [p['revenue'] for p in DATA['product_ranking']] colors = ['#ff5722', '#ff9800', '#ffc107', '#ffeb3b'] bars = ax.bar(products, revenues, color=colors[:len(products)], edgecolor='white', linewidth=2) ax.set_title('产品营收排行(万元)', fontsize=14, fontweight='bold', pad=15) ax.set_ylabel('营收(万元)') ax.grid(True, axis='y', alpha=0.3) for bar, val in zip(bars, revenues): ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1, f'{val}', ha='center', va='bottom', fontsize=11, fontweight='bold') plt.tight_layout() return fig def plot_pie_chart(): """绘制产品营收占比饼图""" fig, ax = plt.subplots(figsize=(7, 5)) products = [p['name'] for p in DATA['product_ranking']] revenues = [p['revenue'] for p in DATA['product_ranking']] colors = ['#2196f3', '#4caf50', '#ff9800', '#9c27b0'] explode = (0.05, 0, 0, 0) wedges, texts, autotexts = ax.pie(revenues, labels=products, autopct='%1.1f%%', startangle=90, colors=colors[:len(products)], explode=explode[:len(products)]) ax.set_title('产品营收占比', fontsize=14, fontweight='bold', pad=15) for autotext in autotexts: autotext.set_color('white') autotext.set_fontweight('bold') plt.tight_layout() return fig # ================= 3. 生成高清图片并插入 PPT ================= # 创建演示文稿 prs = Presentation() # 使用空白幻灯片布局 blank_slide_layout = prs.slide_layouts[6] slide = prs.slides.add_slide(blank_slide_layout) # 3.1 设置主题标题 title_box = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(9), Inches(0.8)) tf = title_box.text_frame tf.paragraphs[0].text = '产品月报数据看板' tf.paragraphs[0].font.size = Pt(32) tf.paragraphs[0].font.bold = True tf.paragraphs[0].font.color.rgb = _hex_to_rgb('#1976d2') tf.paragraphs[0].alignment = PP_ALIGN.CENTER # 添加日期 date_box = slide.shapes.add_textbox(Inches(7.5), Inches(0.2), Inches(2), Inches(0.5)) tf_date = date_box.text_frame tf_date.paragraphs[0].text = '2026年7月' tf_date.paragraphs[0].font.size = Pt(12) tf_date.paragraphs[0].font.color.rgb = _hex_to_rgb('#999999') # 3.2 添加核心KPI卡片 kpis = [ {'title': '总营收', 'value': DATA['revenue'], 'unit': '万元', 'growth': DATA['revenue_growth'], 'color': '#1976d2'}, {'title': '活跃用户', 'value': DATA['users'], 'unit': '万人', 'growth': DATA['users_growth'], 'color': '#4caf50'}, {'title': '转化率', 'value': DATA['conversion_rate'], 'unit': '%', 'growth': DATA['conversion_change'], 'color': '#ff9800'}, {'title': '留存率', 'value': DATA['retention_rate'], 'unit': '%', 'growth': 0, 'color': '#9c27b0'}, ] for i, kpi in enumerate(kpis): x_pos = 0.5 + i * 2.4 # 卡片背景(通过添加矩形形状作为背景) rect = slide.shapes.add_shape(1, Inches(x_pos), Inches(0.9), Inches(2.2), Inches(1.1)) rect.fill.solid() rect.fill.fore_color.rgb = _hex_to_rgb(kpi['color']) rect.line.color.rgb = _hex_to_rgb('#ffffff') # 标题 add_textbox(slide, kpi['title'], x_pos + 0.1, 0.98, 2.0, 0.3, font_size=11, color='#ffffff') # 值 value_text = f"{kpi['value']}{kpi['unit']}" add_textbox(slide, value_text, x_pos + 0.1, 1.2, 2.0, 0.4, font_size=20, bold=True, color='#ffffff') # 增长率/变化(如果存在) if kpi.get('growth'): icon = get_up_down_icon(kpi['growth']) growth_text = f"{icon} {abs(kpi['growth'])}{kpi['unit'] if kpi['unit'] != '%' else 'pp' if kpi['title'] == '转化率' else '%'}" add_textbox(slide, growth_text, x_pos + 0.1, 1.55, 2.0, 0.3, font_size=9, color='#ffffff') # 3.3 添加营收趋势图 print("正在生成营收趋势图...") line_fig = plot_line_chart() save_chart_and_insert_to_ppt(plt, line_fig, slide, left=0.5, top=2.2, width=5.5, height=2.2, dpi=300, filename='revenue_trend.png') # 3.4 添加产品营收排行图(柱状图) print("正在生成产品营收排行...") bar_fig = plot_bar_chart() save_chart_and_insert_to_ppt(plt, bar_fig, slide, left=6.5, top=2.2, width=3.2, height=2.2, dpi=300, filename='product_ranking.png') # 3.5 添加产品营收占比图(饼图) print("正在生成产品营收占比...") pie_fig = plot_pie_chart() save_chart_and_insert_to_ppt(plt, pie_fig, slide, left=0.5, top=4.5, width=4.2, height=2.2, dpi=300, filename='product_pie.png') # 3.6 添加总结说明文本框 summary_text = ( "数据分析总结:\n" f"• 7月总营收达{DATA['revenue']}万元,环比增长{DATA['revenue_growth']}%,\n连续7个月保持增长态势\n" f"• 活跃用户突破{DATA['users']}万人,用户增长持续健康\n" f"• 产品A营收占比最高,贡献总营收{DATA['product_ranking'][0]['revenue'] / DATA['revenue'] * 100:.1f}%\n" "• 转化率环比提升3.2个百分点,运营策略效果显著" ) add_textbox(slide, summary_text, 5.2, 4.9, 4.5, 2.0, font_size=9, color='#555555') # 设置文本框左对齐 summary_box = slide.shapes[-1] summary_box.text_frame.paragraphs[0].alignment = PP_ALIGN.LEFT # 3.7 添加图例说明 legend_text = "数据来源: 内部数据系统 | 更新日期: 2026-07-31" add_textbox(slide, legend_text, 6.8, 5.6, 2.8, 0.3, font_size=8, color='#999999') # 设置图例右对齐 legend_box = slide.shapes[-1] legend_box.text_frame.paragraphs[0].alignment = PP_ALIGN.RIGHT # ================= 4. 导出 PPT 文件 ================= ppt_filename = 'product_monthly_report.pptx' prs.save(ppt_filename) print(f"\n✅ PPT 文件已生成: {ppt_filename}") # ================= 5. 导出整页为高清 PNG ================= print("\n💡 提示: 可通过 PowerPoint 手动导出为图片,或使用拓展方案生成完整高清看板") if __name__ == '__main__': create_dashboard() # 交互式HTML看板备选方案提示 print("\n备选方案: 如需生成可交互的 HTML 看板,可以使用 pyecharts") |