# cpdtab2 三下划线多维表格测试报告

## 测试日期
2025-10-16

## 更新日期
2025-10-16 (升级：Subtotal 格式化 + Index 列宽自动调整)

## 测试目的
验证 `cpdtab2` 方法结合 `putxl` 导出时，使用三下划线 (`___`) 分割创建的多维表格功能是否正常，特别是：
1. 多个 index 和多个 columns 的正确生成
2. `auto_format` 自动合并 index 和 column 非最后一级单元格
3. Total 列和 Total 行的位置正确性
4. Subtotal 功能的正确性

## 测试文件
- 测试脚本: `test_cpdtab2_triple_underscore.py`
- 输出文件: `test_cpdtab2_triple_underscore.xlsx`

## 测试用例

### 测试 1: 双 index, 双 columns (无 Subtotal)
**方法**: `df.cpdtab2_Region__Category___Quarter__Product`

**预期结果**:
- Index: Region, Category (2级)
- Columns: Quarter, Product (2级)
- Region (第一级) 应被合并且居中
- Category (最后一级) 不应被合并
- Quarter (第一级) 应被合并且居中
- Product (最后一级) 不应被合并

**实际结果**: ✅ **通过**
- Region 合并: A3:A5 (居中)
- Quarter 合并: C1:E1 (居中)
- Category 和 Product 保持不合并

### 测试 2: 双 index, 双 columns (带 Subtotal)
**方法**: `df.cpdtab2s_Region__Category___Quarter__Product`

**预期结果**:
- 包含 Subtotal 行（每个 Region 一个）
- 包含 Subtotal 列（每个 Quarter 一个）
- Total 行在最下方
- Total 列在最右边
- Region 合并应包含 Subtotal 行

**实际结果**: ✅ **通过**
- Region 合并: A3:A6 (包含 Subtotal 行，居中)
- Quarter 合并: C1:F1 (包含 Subtotal 列，居中)
- 找到 4 个 Subtotal 行（华东、华北、华南、西南）
- 找到 4 个 Subtotal 列（Q1-Q4）
- Total 行在第 19 行（最后）
- Total 列在最右边

### 测试 3: 三 index, 单 column (带 Subtotal 和 sum 聚合)
**方法**: `df.cpdtab2ssum_Region__Category__Product___Quarter__Sales`

**预期结果**:
- Index: Region, Category, Product (3级)
- Columns: Quarter (1级)
- Region 和 Category 应被合并
- Product (最后一级) 不应被合并
- Subtotal 行在每个 Region 的最后

**实际结果**: ✅ **通过**
- Region 合并: A2:A11 (包含 Subtotal 行，居中)
- 找到 Subtotal 行在正确位置
- Total 行在第 42 行（最后）

### 测试 4: 单 index, 三 columns (带 Subtotal)
**方法**: `df.cpdtab2s_Region___Quarter__Category__Product`

**预期结果**:
- Index: Region (1级，不需要合并)
- Columns: Quarter, Category, Product (3级)
- Quarter 和 Category 应被合并
- Product (最后一级) 不应被合并

**实际结果**: ✅ **通过**
- Region 不合并（单级 index）
- Quarter 合并: B1:K1 (居中)

### 测试 5: 双 index, 双 columns (无 Subtotal，对比测试)
**方法**: `df.cpdtab2_Region__Category___Quarter__Product`

**预期结果**:
- 与测试 1 相同，但用于对比验证

**实际结果**: ✅ **通过**
- Region 合并: A3:A5 (居中)
- Quarter 合并: C1:E1 (居中)

## 自动格式化验证

### Header 格式
- ✅ 蓝色背景 (#4472C4)
- ✅ 白色字体
- ✅ 粗体
- ✅ 居中对齐
- ✅ 自动换行

### 合并单元格
- ✅ MultiIndex index 的前 N-1 级被合并且居中
- ✅ MultiIndex columns 的前 N-1 级被合并且居中
- ✅ 最后一级的 index 和 columns 保持不合并
- ✅ 合并的单元格水平对齐为居中 (Center)

### Subtotal 功能
- ✅ Subtotal 行在每个第一级 index 分组的最后
- ✅ Subtotal 列在每个第一级 column 分组的最后
- ✅ Subtotal 行被正确包含在 index 合并范围内
- ✅ Total 行始终在表格最下方
- ✅ Total 列始终在表格最右边

### 边框
- ✅ 整体外框为粗黑边框
- ✅ Header 外框为粗黑边框
- ✅ Index 外框为粗黑边框
- ✅ 每个第一级 index 分组有分区边框
- ✅ 每个第一级 column 分组的首列有粗左边框

### Subtotal 格式化 (新增)
- ✅ Subtotal 行字体加粗
- ✅ Subtotal 行填充 lightgray (#D3D3D3) 背景色
- ✅ Subtotal 列字体加粗
- ✅ Subtotal 列填充 lightgray (#D3D3D3) 背景色

### Index 列宽自动调整 (新增)
- ✅ Index 列宽自动适应内容
- ✅ 所有 index 列（Region, Category, Product 等）都正确调整

### 其他
- ✅ 网格线已启用
- ✅ 数据区域的 0 值被替换为空白（np.nan）

## 修复的问题

### 问题 1: ValueError - Grouper not 1-dimensional
**原因**: 在选择 `idvar`（用于 count 的列）时，可能选中了已经在 `pivot_index` 或 `pivot_columns` 中的列，导致 pandas 在计算 margins 时出错。

**解决方案**: 修改 `idvar` 选择逻辑，确保选择的列不在 `pivot_index` 或 `pivot_columns` 中。

**修改文件**: `pandaspro/core/frame.py`

**修改内容**:
```python
# 选择 idvar，确保不在 index 或 columns 中
if self.uid is None:
    # 获取所有不在 pivot_index 和 pivot_columns 中的列
    used_fields = set(pivot_index if isinstance(pivot_index, list) else [pivot_index])
    used_fields.update(pivot_columns if isinstance(pivot_columns, list) else [pivot_columns])
    available_cols = [col for col in self.columns[self.notnull().all()].tolist() if col not in used_fields]
    if available_cols:
        idvar = available_cols[0]
    else:
        # 如果没有可用的列，使用第一个非空列（即使它在 index/columns 中）
        idvar = self.columns[self.notnull().all()].tolist()[0]
else:
    idvar = self.uid
```

### 问题 2: 三下划线解析逻辑优化
**改进**: 
- 移除了对 `_parse_and_match` 的不必要调用
- 增加了对字段解析的验证，确保所有字段都能被找到
- 增加了更清晰的错误消息

**修改文件**: `pandaspro/core/frame.py`

**影响的方法**:
- `cpdtab2_` (第387-465行)
- `cpdtab2s_` (第336-404行)
- `cpdtab2s{aggfunc}_` (第458-523行)
- `cpdtab2{aggfunc}_` (第525-590行)

## 总结

所有测试用例均已通过。`cpdtab2` 方法结合 `putxl` 导出的多维表格功能完全正常，包括：

1. ✅ 三下划线 (`___`) 正确分割 index 和 columns
2. ✅ 自动格式化正确合并 index 和 column 的非最后一级单元格
3. ✅ 合并的单元格正确居中对齐
4. ✅ Subtotal 行和列位置正确
5. ✅ Total 行在最下方，Total 列在最右边
6. ✅ 所有边框、颜色、对齐等格式正确应用
7. ✅ **Subtotal 行和列加粗且填充 lightgray 背景色 (新增)**
8. ✅ **Index 列宽自动调整以适应内容 (新增)**

## 建议

1. 可以继续使用 `cpdtab2` 系列方法创建多维透视表
2. 建议使用 `auto_format=True` 和 `index_auto_merge=True` 获得最佳视觉效果
3. 对于复杂的多维表格，使用三下划线 (`___`) 明确指定 index 和 columns 的字段
4. 使用 `cpdtab2s` 系列方法可以自动添加 Subtotal，提供更好的数据汇总

## 最新更新 (2025-10-16)

### 新增功能

#### 1. Subtotal 格式化
自动为所有 Subtotal 行和列应用特殊格式：
- **加粗字体**：使 Subtotal 更加突出
- **Lightgray 背景** (#D3D3D3)：与普通数据区分开来

**实现位置**：
- `pandaspro/io/excel/writer.py` - 添加了 `range_subtotal_rows()` 和 `range_subtotal_columns()` 方法
- `pandaspro/io/excel/putexcel.py` - 在 `auto_format` 部分应用格式

**使用方法**：
```python
df.cpdtab2s_Region__Category___Quarter__Product
# Subtotal 行和列会自动加粗并填充 lightgray 背景
```

#### 2. Index 列宽自动调整
自动调整 index 列的宽度以适应内容，无需手动设置。

**实现位置**：
- `pandaspro/io/excel/putexcel.py` - 在 `auto_format` 部分调用 `columns.autofit()`

**效果**：
- Region, Category, Product 等 index 列宽度自动适应内容
- 避免内容被截断或列宽过宽

## 相关文件

- 核心逻辑: `pandaspro/core/frame.py`
- 导出逻辑: `pandaspro/io/excel/putexcel.py`
- Writer 逻辑: `pandaspro/io/excel/writer.py` (新增方法)
- 测试脚本: `pandaspro/test/test_cpdtab2_triple_underscore.py`

