|
|
@@ -65,7 +65,8 @@ daily = df.groupby(['dt', 'channel']).apply(
|
|
|
# ============================================================
|
|
|
|
|
|
# 主要渠道(UV > 10000)
|
|
|
-main_channels = channel_stats[channel_stats['点击uv'] > 10000]['channel'].tolist()[:8]
|
|
|
+# 选择 UV > 10000 的所有渠道
|
|
|
+main_channels = channel_stats[channel_stats['点击uv'] > 10000]['channel'].tolist()
|
|
|
valid_categories = pivot_uv[pivot_uv.sum(axis=1) >= 1000].index.tolist()
|
|
|
heatmap_cols = [c for c in main_channels if c in pivot_ror.columns]
|
|
|
|
|
|
@@ -80,15 +81,18 @@ for _, row in channel_stats.iterrows():
|
|
|
f"<td><div style='background:#007bff;height:20px;width:{bar_width}%'></div></td></tr>"
|
|
|
)
|
|
|
|
|
|
-# 2. 回流率热力图
|
|
|
-def get_cell_class(val):
|
|
|
- if val is None:
|
|
|
- return ""
|
|
|
- if val > 0.30:
|
|
|
- return "high"
|
|
|
- if val > 0.15:
|
|
|
- return "medium"
|
|
|
- return "low"
|
|
|
+# 2. 回流率热力图 - 根据数值渐变颜色
|
|
|
+def get_ror_color(val, max_val=0.5):
|
|
|
+ """回流率颜色:白色(0) -> 绿色(max)"""
|
|
|
+ if val is None or val <= 0:
|
|
|
+ return "background: #f8f9fa"
|
|
|
+ ratio = min(val / max_val, 1.0)
|
|
|
+ # 白色到绿色渐变
|
|
|
+ r = int(255 - ratio * 215) # 255 -> 40
|
|
|
+ g = int(255 - ratio * 88) # 255 -> 167
|
|
|
+ b = int(255 - ratio * 186) # 255 -> 69
|
|
|
+ text_color = "white" if ratio > 0.5 else "black"
|
|
|
+ return f"background: rgb({r},{g},{b}); color: {text_color}"
|
|
|
|
|
|
ror_header = "<tr><th>品类</th>" + "".join([f"<th>{c[:10]}</th>" for c in heatmap_cols]) + "</tr>"
|
|
|
ror_rows = []
|
|
|
@@ -97,21 +101,24 @@ for cat in valid_categories:
|
|
|
for ch in heatmap_cols:
|
|
|
if ch in pivot_ror.columns and pd.notna(pivot_ror.loc[cat, ch]):
|
|
|
val = pivot_ror.loc[cat, ch]
|
|
|
- cls = get_cell_class(val)
|
|
|
- cells.append(f'<td class="{cls}">{val:.4f}</td>')
|
|
|
+ style = get_ror_color(val)
|
|
|
+ cells.append(f'<td style="{style}">{val:.4f}</td>')
|
|
|
else:
|
|
|
cells.append("<td>-</td>")
|
|
|
ror_rows.append("<tr>" + "".join(cells) + "</tr>")
|
|
|
|
|
|
-# 3. UV分布热力图
|
|
|
-def get_uv_class(val):
|
|
|
- if val >= 50000:
|
|
|
- return "high"
|
|
|
- if val >= 10000:
|
|
|
- return "medium"
|
|
|
- if val >= 1000:
|
|
|
- return "low"
|
|
|
- return ""
|
|
|
+# 3. UV分布热力图 - 根据数值渐变颜色
|
|
|
+def get_uv_color(val, max_val=100000):
|
|
|
+ """UV颜色:白色(0) -> 蓝色(max)"""
|
|
|
+ if val is None or val <= 0:
|
|
|
+ return "background: #f8f9fa"
|
|
|
+ ratio = min(val / max_val, 1.0)
|
|
|
+ # 白色到蓝色渐变
|
|
|
+ r = int(255 - ratio * 201) # 255 -> 54
|
|
|
+ g = int(255 - ratio * 93) # 255 -> 162
|
|
|
+ b = int(255 - ratio * 20) # 255 -> 235
|
|
|
+ text_color = "white" if ratio > 0.5 else "black"
|
|
|
+ return f"background: rgb({r},{g},{b}); color: {text_color}"
|
|
|
|
|
|
uv_header = "<tr><th>品类</th>" + "".join([f"<th>{c[:10]}</th>" for c in heatmap_cols]) + "</tr>"
|
|
|
uv_rows = []
|
|
|
@@ -121,8 +128,8 @@ for cat in valid_categories:
|
|
|
if ch in pivot_uv.columns:
|
|
|
val = pivot_uv.loc[cat, ch]
|
|
|
if val > 0:
|
|
|
- cls = get_uv_class(val)
|
|
|
- cells.append(f'<td class="{cls}">{int(val):,}</td>')
|
|
|
+ style = get_uv_color(val)
|
|
|
+ cells.append(f'<td style="{style}">{int(val):,}</td>')
|
|
|
else:
|
|
|
cells.append("<td>-</td>")
|
|
|
else:
|
|
|
@@ -135,12 +142,26 @@ pivot_recommend = df.groupby(['channel', 'merge一级品类']).apply(
|
|
|
include_groups=False
|
|
|
).unstack()
|
|
|
|
|
|
-def get_recommend_class(val):
|
|
|
+def get_recommend_color(val):
|
|
|
+ """推荐率颜色:红色(低) -> 黄色(中) -> 绿色(高)"""
|
|
|
+ if val is None:
|
|
|
+ return "background: #f8f9fa"
|
|
|
if val >= 0.8:
|
|
|
- return "high"
|
|
|
- if val >= 0.7:
|
|
|
- return "medium"
|
|
|
- return "low"
|
|
|
+ ratio = min((val - 0.8) / 0.2, 1.0)
|
|
|
+ r, g, b = 40, 167, 69 # 绿色
|
|
|
+ elif val >= 0.7:
|
|
|
+ ratio = (val - 0.7) / 0.1
|
|
|
+ r = int(255 - ratio * 215)
|
|
|
+ g = int(193 - ratio * 26)
|
|
|
+ b = int(7 + ratio * 62)
|
|
|
+ else:
|
|
|
+ ratio = val / 0.7
|
|
|
+ r, g, b = 220, 53, 69 # 红色基础
|
|
|
+ r = int(255 - ratio * 35)
|
|
|
+ g = int(255 - ratio * 62)
|
|
|
+ b = int(255 - ratio * 248)
|
|
|
+ text_color = "white" if val >= 0.75 or val < 0.65 else "black"
|
|
|
+ return f"background: rgb({r},{g},{b}); color: {text_color}"
|
|
|
|
|
|
recommend_rows = []
|
|
|
for cat in valid_categories:
|
|
|
@@ -148,8 +169,8 @@ for cat in valid_categories:
|
|
|
for ch in heatmap_cols:
|
|
|
if ch in pivot_recommend.columns and cat in pivot_recommend.index and pd.notna(pivot_recommend.loc[cat, ch]):
|
|
|
val = pivot_recommend.loc[cat, ch]
|
|
|
- cls = get_recommend_class(val)
|
|
|
- cells.append(f'<td class="{cls}">{val:.4f}</td>')
|
|
|
+ style = get_recommend_color(val)
|
|
|
+ cells.append(f'<td style="{style}">{val:.4f}</td>')
|
|
|
else:
|
|
|
cells.append("<td>-</td>")
|
|
|
recommend_rows.append("<tr>" + "".join(cells) + "</tr>")
|
|
|
@@ -186,8 +207,8 @@ for cat2 in valid_cat2_labels:
|
|
|
for ch in heatmap_cols:
|
|
|
if ch in pivot_cat2_ror.columns and pd.notna(pivot_cat2_ror.loc[cat2, ch]):
|
|
|
val = pivot_cat2_ror.loc[cat2, ch]
|
|
|
- cls = get_cell_class(val)
|
|
|
- cells.append(f'<td class="{cls}">{val:.4f}</td>')
|
|
|
+ style = get_ror_color(val)
|
|
|
+ cells.append(f'<td style="{style}">{val:.4f}</td>')
|
|
|
else:
|
|
|
cells.append("<td>-</td>")
|
|
|
cat2_ror_rows.append("<tr>" + "".join(cells) + "</tr>")
|
|
|
@@ -202,8 +223,8 @@ for cat2 in valid_cat2_labels:
|
|
|
if ch in pivot_cat2_uv.columns:
|
|
|
val = pivot_cat2_uv.loc[cat2, ch]
|
|
|
if val > 0:
|
|
|
- cls = get_uv_class(val)
|
|
|
- cells.append(f'<td class="{cls}">{int(val):,}</td>')
|
|
|
+ style = get_uv_color(val)
|
|
|
+ cells.append(f'<td style="{style}">{int(val):,}</td>')
|
|
|
else:
|
|
|
cells.append("<td>-</td>")
|
|
|
else:
|
|
|
@@ -325,11 +346,7 @@ html_content = f"""<!DOCTYPE html>
|
|
|
|
|
|
<h2>2. 渠道×品类 回流率矩阵</h2>
|
|
|
<div class="chart-container heatmap matrix-section">
|
|
|
- <div class="legend">
|
|
|
- <span class="high">高 >0.30</span>
|
|
|
- <span class="medium">中 0.15-0.30</span>
|
|
|
- <span class="low">低 <0.15</span>
|
|
|
- </div>
|
|
|
+ <div class="legend">颜色越深=回流率越高(白→绿渐变,max=0.50)</div>
|
|
|
<table>
|
|
|
{ror_header}
|
|
|
{"".join(ror_rows)}
|
|
|
@@ -338,11 +355,7 @@ html_content = f"""<!DOCTYPE html>
|
|
|
|
|
|
<h2>3. 渠道×品类 点击UV矩阵</h2>
|
|
|
<div class="chart-container heatmap matrix-section">
|
|
|
- <div class="legend">
|
|
|
- <span class="high">高 >5万</span>
|
|
|
- <span class="medium">中 1-5万</span>
|
|
|
- <span class="low">低 <1万</span>
|
|
|
- </div>
|
|
|
+ <div class="legend">颜色越深=UV越高(白→蓝渐变,max=10万)</div>
|
|
|
<table>
|
|
|
{uv_header}
|
|
|
{"".join(uv_rows)}
|
|
|
@@ -351,11 +364,7 @@ html_content = f"""<!DOCTYPE html>
|
|
|
|
|
|
<h2>4. 渠道×品类 进入推荐率矩阵</h2>
|
|
|
<div class="chart-container heatmap matrix-section">
|
|
|
- <div class="legend">
|
|
|
- <span class="high">高 >0.80</span>
|
|
|
- <span class="medium">中 0.70-0.80</span>
|
|
|
- <span class="low">低 <0.70</span>
|
|
|
- </div>
|
|
|
+ <div class="legend">颜色:红(<0.70) → 黄(0.70-0.80) → 绿(>0.80)</div>
|
|
|
<table>
|
|
|
{ror_header}
|
|
|
{"".join(recommend_rows)}
|
|
|
@@ -364,11 +373,7 @@ html_content = f"""<!DOCTYPE html>
|
|
|
|
|
|
<h2>5. 渠道×二级品类 回流率矩阵</h2>
|
|
|
<div class="chart-container heatmap matrix-section">
|
|
|
- <div class="legend">
|
|
|
- <span class="high">高 >0.30</span>
|
|
|
- <span class="medium">中 0.15-0.30</span>
|
|
|
- <span class="low">低 <0.15</span>
|
|
|
- </div>
|
|
|
+ <div class="legend">颜色越深=回流率越高(白→绿渐变,max=0.50)</div>
|
|
|
<table>
|
|
|
{cat2_ror_header}
|
|
|
{"".join(cat2_ror_rows)}
|
|
|
@@ -377,11 +382,7 @@ html_content = f"""<!DOCTYPE html>
|
|
|
|
|
|
<h2>6. 渠道×二级品类 点击UV矩阵</h2>
|
|
|
<div class="chart-container heatmap matrix-section">
|
|
|
- <div class="legend">
|
|
|
- <span class="high">高 >5万</span>
|
|
|
- <span class="medium">中 1-5万</span>
|
|
|
- <span class="low">低 <1万</span>
|
|
|
- </div>
|
|
|
+ <div class="legend">颜色越深=UV越高(白→蓝渐变,max=10万)</div>
|
|
|
<table>
|
|
|
{cat2_ror_header}
|
|
|
{"".join(cat2_uv_rows)}
|