mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-22 08:01:34 +08:00
fix(report): 细类扇图口径与版式统一
_category_mix 增加(其余细类)使简报与扇形图合计等于有效矩阵 SKU 数;§4.3 去掉易与图不一致的 Markdown 表格与规则摘要,仅保留扇形图;全部扇形图默认画布统一为 4.9×3.65 英寸。 Made-with: Cursor
This commit is contained in:
parent
99d1b23b63
commit
30a6bc4405
@ -1677,13 +1677,26 @@ def _category_mix(
|
||||
"""
|
||||
按「可读细类标签」统计 SKU 分布(与 §5 ``_competitor_matrix_group_key`` 同源);
|
||||
仅含 ``detail_category_path`` 可解析为展示名的行。
|
||||
|
||||
返回 ``most_common(top_k)``,并将未列入 Top K 的款数合并为「(其余细类)」,
|
||||
使各块 SKU 数之和等于有效矩阵 SKU 总数(与扇形图、简报 ``category_mix_top`` 一致)。
|
||||
"""
|
||||
labels: list[str] = []
|
||||
for r in rows:
|
||||
k = _matrix_group_label_from_detail_path(r)
|
||||
if k:
|
||||
labels.append(k)
|
||||
return Counter(labels).most_common(top_k)
|
||||
if not labels:
|
||||
return []
|
||||
c = Counter(labels)
|
||||
common = c.most_common(top_k)
|
||||
accounted = sum(v for _, v in common)
|
||||
total = sum(c.values())
|
||||
rest = total - accounted
|
||||
out: list[tuple[str, int]] = list(common)
|
||||
if rest > 0:
|
||||
out.append(("(其余细类)", rest))
|
||||
return out
|
||||
|
||||
|
||||
def _structure_shops(rows: list[dict[str, str]], *, list_export: bool) -> list[str]:
|
||||
@ -1948,38 +1961,6 @@ def _lines_4_reading_shop(
|
||||
return lines
|
||||
|
||||
|
||||
def _lines_4_reading_category(
|
||||
cm_structure: list[tuple[str, int]],
|
||||
*,
|
||||
n_merged_sku: int,
|
||||
n_sku_matrix: int,
|
||||
) -> list[str]:
|
||||
if not cm_structure or n_sku_matrix <= 0:
|
||||
return []
|
||||
top_lbl, top_c = cm_structure[0]
|
||||
share = top_c / float(n_sku_matrix)
|
||||
lines = [
|
||||
"",
|
||||
"**数据解读(规则摘要)**:",
|
||||
"",
|
||||
f"- **统计口径**:与 **§5 竞品矩阵**相同,均来自深入合并表列 ``detail_category_path`` 解析出的可读细类标签。",
|
||||
f"- **有效总量**:合并表共 **{n_merged_sku}** 个 SKU;其中 **{n_sku_matrix}** 个具备可解析细类标签(**有效细类 SKU**);"
|
||||
f"**{max(0, n_merged_sku - n_sku_matrix)}** 个无可用路径或无法解析,与 §5 一致**不纳入**本小节分布。",
|
||||
f"- 扇形图与简报包按 SKU 数取 **Top 12** 细类;下表列 **Top 5**。当前「{_md_cell(top_lbl, 40)}」款数最多,"
|
||||
f"约占有效细类 SKU 的 **{100 * share:.1f}%**({top_c}/{n_sku_matrix})。",
|
||||
"- 若头部细类占比极高,说明当前关键词下深入样本被少数品类定义;跨品类机会需结合 §5 矩阵再核对。",
|
||||
"",
|
||||
"| 细类标签(Top 5) | SKU 数 | 占有效细类 SKU 数 |",
|
||||
"| --- | ---: | ---: |",
|
||||
]
|
||||
for lbl, cnt in cm_structure[:5]:
|
||||
lines.append(
|
||||
f"| {_md_cell(lbl, 36)} | {cnt} | {100 * cnt / float(n_sku_matrix):.1f}% |"
|
||||
)
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
|
||||
def build_competitor_markdown(
|
||||
*,
|
||||
run_dir: Path,
|
||||
@ -2415,14 +2396,8 @@ def build_competitor_markdown(
|
||||
_embed_chart(
|
||||
run_dir,
|
||||
"chart_category_mix_pie.png",
|
||||
"细类标签分布(扇形图;合并表 ``detail_category_path``,与 §5 同源)",
|
||||
)
|
||||
)
|
||||
lines.extend(
|
||||
_lines_4_reading_category(
|
||||
cm_structure,
|
||||
n_merged_sku=n_sku,
|
||||
n_sku_matrix=n_sku_matrix,
|
||||
"细类标签分布(扇形图;合并表 ``detail_category_path``,与 §5 同源;"
|
||||
"Top 12 以外的细类在数据层并入「(其余细类)」;扇形图内再合并为「其他」)",
|
||||
)
|
||||
)
|
||||
lines.append(
|
||||
|
||||
@ -473,7 +473,7 @@ def generate_report_charts(run_dir: Path, brief: dict[str, Any]) -> list[str]:
|
||||
labs, vals = _merge_tail_as_other(labels, values, max_slices=max_slices)
|
||||
if not labs or not vals or sum(vals) <= 0:
|
||||
return
|
||||
fs = figsize if figsize is not None else (6.2, 4.5)
|
||||
fs = figsize if figsize is not None else (4.9, 3.65)
|
||||
fig, ax = plt.subplots(figsize=fs)
|
||||
colors = plt.cm.Set3(range(len(labs)))
|
||||
wedges, _t, autotexts = ax.pie(
|
||||
@ -524,7 +524,6 @@ def generate_report_charts(run_dir: Path, brief: dict[str, Any]) -> list[str]:
|
||||
vb,
|
||||
"品牌列表曝光占比",
|
||||
"chart_brand_rows_pie.png",
|
||||
figsize=(4.9, 3.65),
|
||||
)
|
||||
|
||||
shop_mix = brief.get("list_shop_mix_top") or []
|
||||
@ -534,7 +533,6 @@ def generate_report_charts(run_dir: Path, brief: dict[str, Any]) -> list[str]:
|
||||
vs,
|
||||
"店铺列表曝光占比",
|
||||
"chart_shop_rows_pie.png",
|
||||
figsize=(4.9, 3.65),
|
||||
)
|
||||
|
||||
def scenario_group_asset_slug(group: str, index: int) -> str:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user