# 出图（Python 路线）· 课堂演示件
#
# 作用：读取 第15章演示_汇总数据.csv，画两张图并存成 png。
# 用法：pip install matplotlib
#       直接运行。图片存在本文件旁边。
#
# 把设置区的 USE_CHINESE_FONT 改成 False 再跑一次，可以看到中文变方块是什么样。

import csv
from pathlib import Path

import matplotlib
matplotlib.use('Agg')          # 不弹窗，直接出图片文件
import matplotlib.pyplot as plt
from matplotlib import font_manager

# ===== 设置区 =====
CSV = '第15章演示_汇总数据.csv'
USE_CHINESE_FONT = True        # 改成 False 可复现「中文变方块」
DPI = 150                      # 分辨率。放进文档 150 够用，投影用 200
# =================

HERE = Path(__file__).parent


# ① 找一个系统里装着的中文字体。绘图库默认字体不含中文，不设就是方块
def setup_font():
    if not USE_CHINESE_FONT:
        print('已关闭中文字体，中文将显示为方块')
        return
    候选 = ['Microsoft YaHei', 'SimHei', 'PingFang SC', 'Heiti SC',
            'Noto Sans CJK SC', 'Noto Sans CJK JP', 'WenQuanYi Zen Hei', 'Source Han Sans SC']
    有的 = {f.name for f in font_manager.fontManager.ttflist}
    for name in 候选:
        if name in 有的:
            plt.rcParams['font.sans-serif'] = [name]
            plt.rcParams['axes.unicode_minus'] = False   # 负号也要用这套字体
            print('使用中文字体：', name)
            return
    print('没有找到可用的中文字体，中文会显示为方块。')
    print('候选字体：', '、'.join(候选))


# ② 读数据
def read_data():
    with open(HERE / CSV, encoding='utf-8-sig', newline='') as fp:
        rows = list(csv.DictReader(fp))
    classes = [c for c in rows[0].keys() if c != '月份']
    months = [r['月份'] for r in rows]
    totals = {c: sum(int(r[c]) for r in rows) for c in classes}
    monthly = [sum(int(r[c]) for c in classes) for r in rows]
    return classes, months, totals, monthly


# ③ 柱状图：比大小。纵轴一律从 0 起
def draw_bar(classes, totals):
    fig, ax = plt.subplots(figsize=(6, 4))
    ax.bar(classes, [totals[c] for c in classes], width=0.5, color='#2f6b45')
    for i, c in enumerate(classes):
        ax.text(i, totals[c] + 6, str(totals[c]), ha='center', fontsize=11,
                fontweight='bold', color='#2f6b45')
    ax.set_ylim(0, 350)                       # 从 0 起，不要截断
    ax.set_title('各班学期总参与人次')
    ax.set_ylabel('人次')
    ax.spines['top'].set_visible(False)       # 去掉不承载信息的边框
    ax.spines['right'].set_visible(False)
    ax.grid(axis='y', color='#dfe4dd', linewidth=0.8)
    ax.set_axisbelow(True)
    fig.text(0.01, 0.01, '数据来源：书院读书活动签到记录｜统计范围：2026 年 3 月至 8 月',
             fontsize=8, color='#6f7d73')
    fig.tight_layout(rect=(0, 0.04, 1, 1))
    out = HERE / '图1_各班总人次.png'
    fig.savefig(out, dpi=DPI)
    plt.close(fig)
    return out


# ④ 折线图：看变化。纵轴可以不从 0 起，但起点要标清楚
def draw_line(months, monthly):
    fig, ax = plt.subplots(figsize=(6, 4))
    ax.plot(months, monthly, marker='o', linewidth=2.2, color='#2f6b45',
            markerfacecolor='white', markeredgewidth=2)
    for i, v in enumerate(monthly):
        ax.text(i, v + 1.6, str(v), ha='center', fontsize=10,
                fontweight='bold', color='#2f6b45')
    ax.set_ylim(120, 170)
    ax.set_title('全院逐月参与人次')
    ax.set_ylabel('人次')
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.grid(axis='y', color='#dfe4dd', linewidth=0.8)
    ax.set_axisbelow(True)
    fig.text(0.01, 0.01, '纵轴自 120 起｜数据来源：书院读书活动签到记录｜2026 年 3 月至 8 月',
             fontsize=8, color='#6f7d73')
    fig.tight_layout(rect=(0, 0.04, 1, 1))
    out = HERE / '图2_逐月人次.png'
    fig.savefig(out, dpi=DPI)
    plt.close(fig)
    return out


setup_font()
classes, months, totals, monthly = read_data()
print('各班合计：', totals)
print('已生成', draw_bar(classes, totals).name)
print('已生成', draw_line(months, monthly).name)
input('按回车键结束')
