查看全课大纲(第 42 / 45 节)
- 1.课程简介
- 2.环境搭建
- 3.预备知识
- 4.pyecharts初体验
- 5.数据可视化概述
- 6.数据可视化的目标和作用
- 7.数据可视化工具对比分析
- 8.数据可视化基本流程
- 9.数据可视化设计原则
- 10.pyecharts简介
- 11.官方图表样例
- 12.常用图表的基本结构
- 13.数据格式
- 14.图表的分类
- 15.柱状图与条形图
- 16.其他对比图表
- 17.常用配置项(一)
- 18.常用配置项(二)
- 19.折线图 面积图
- 20.K线图
- 21.其他时间图表
- 22.常用配置项
- 23.散点图 气泡图
- 24.热力图
- 25.其他相关性图表
- 26.饼图
- 27.矩形树图
- 28.其他成分比例图表
- 29.箱型图与直方图
- 30.3D柱状图与折线图
- 31.其他统计图表
- 32.地图 Map
- 33.地理坐标系Geo
- 34.3D 地图
- 35.网络关系图
- 36.主题河流图
- 37.词云图
- 38.组合图表组件
- 39.仪表盘相关图表
- 40.项目介绍
- 41.数据准备
- 42.子图制作(一)
- 43.子图制作(二)
- 44.数据大屏制作
- 45.项目总结
子图制作(一)
流量指标可视化:从日趋势到小时规律
小象实战讲义 · ECharts 数据可视化
在上一节完成数据准备后,我们得到了结构清晰的电商行为数据集。本节从“用户”这一分析维度出发,把点击记录聚合成 PV(页面浏览量)和 UV(独立访客数),再用折线图观察日变化与小时规律,并处理两者量级不同的问题。
💡 核心导读
- 理解指标口径:PV 统计点击次数,UV 按用户去重统计,两者不能混为同一个指标。
- 完成时间聚合:使用 pandas 分别按日期和小时计算 PV、UV。
- 实现双 Y 轴:使用
extend_axis和yaxis_index让不同量级的系列共享横轴、独立使用纵轴。 - 从图到业务结论:识别活动峰值和晚间活跃时段,并说明图表结论必须回到数据口径验证。
一、PV 与 UV:先定义口径,再画图
- PV(Page View):一次页面访问或一次点击记一条,适合衡量整体交互量和活动热度。
- UV(Unique Visitor):统计周期内按
user_id去重后的用户数,适合衡量实际触达人数。
同一个用户的多次点击会累加 PV,但在 UV 中只计一次。因此,“PV 增长”不一定等于“来了更多新用户”,也可能是老用户访问得更频繁。后续图表要同时保留这两类信息。
二、用确定性小样本完成日、小时聚合
下面的数据围绕 12 月 10 日至 16 日构造,其中 12 日点击最多,用于演示活动峰值。每一天使用 4 个稳定用户,因此日 UV 恒为 4;点击统一分布在 18–21 点,用来展示晚间活跃规律。
import pandas as pd
daily_specs = [
("2024-12-10", 11),
("2024-12-11", 14),
("2024-12-12", 65),
("2024-12-13", 18),
("2024-12-14", 15),
("2024-12-15", 13),
("2024-12-16", 12),
]
event_rows = []
for date_text, pv_count in daily_specs:
for offset in range(pv_count):
event_rows.append(
{
"date": pd.Timestamp(date_text),
"hour": 18 + (offset // 4) % 4,
"user_id": 1000 + offset % 4,
}
)
click_df = pd.DataFrame(event_rows)
daily_flow = (
click_df.groupby("date")
.agg(pv=("user_id", "size"), uv=("user_id", "nunique"))
.reset_index()
)
daily_flow["date"] = daily_flow["date"].dt.strftime("%m-%d")
hourly_flow = (
click_df.groupby("hour")
.agg(pv=("user_id", "size"), uv=("user_id", "nunique"))
.reset_index()
.sort_values("hour")
)
print("日流量聚合(示例):")
print(daily_flow.to_string(index=False))
print("\n小时流量聚合(示例):")
print(hourly_flow.to_string(index=False))日流量聚合(示例):
date pv uv
12-10 11 4
12-11 14 4
12-12 65 4
12-13 18 4
12-14 15 4
12-15 13 4
12-16 12 4
小时流量聚合(示例):
hour pv uv
18 43 4
19 40 4
20 39 4
21 26 4解读:12 月 12 日的 PV 明显高于其他日期,对应活动峰值;小时统计中 18 点最高,随后平稳下降。这里的小样本只验证聚合方法,真实项目仍要使用清洗后的完整数据集,不能把示例数值当成业务结论。
三、用双 Y 轴展示日 PV 与 UV
日 PV 在十级到几十级,UV 只有 4。如果两者共用一根纵轴,UV 会贴近底部。双 Y 轴保留同一时间横轴,同时为两个系列设置独立刻度,便于比较趋势是否同步。
from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.globals import CurrentConfig
CurrentConfig.ONLINE_HOST = "assets/"
dates = ["12-10", "12-11", "12-12", "12-13", "12-14", "12-15", "12-16"]
pv_values = [11, 14, 65, 18, 15, 13, 12]
uv_values = [4, 4, 4, 4, 4, 4, 4]
daily_chart = (
Line(init_opts=opts.InitOpts(width="800px", height="420px"))
.add_xaxis(dates)
.add_yaxis(
"日PV",
pv_values,
is_symbol_show=True,
label_opts=opts.LabelOpts(is_show=False),
)
.extend_axis(
yaxis=opts.AxisOpts(
name="日UV",
type_="value",
min_=0,
max_=6,
position="right",
)
)
.add_yaxis(
"日UV",
uv_values,
yaxis_index=1,
is_symbol_show=True,
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="日流量趋势"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
xaxis_opts=opts.AxisOpts(name="日期"),
yaxis_opts=opts.AxisOpts(name="日PV", type_="value", min_=0, max_=70),
legend_opts=opts.LegendOpts(pos_top="8%"),
)
)
daily_chart.render("daily_traffic.html")
print("日趋势图:2 条系列,7 个日期")日趋势图:2 条系列,7 个日期配置关键点:
extend_axis(...)创建额外纵轴,位置设为右侧。yaxis_index=1让“日 UV”映射到扩展轴;默认主轴索引是 0。- 两条系列共用一个 X 轴,因此能对齐同一天的活动峰值与用户规模。
四、小时流量图与解读边界
小时图沿用相同结构。这里 18 点 PV 最高,随后逐步下降;由于每个时段都只有 4 个用户,UV 曲线保持水平。它能说明“访问次数在晚间最集中”,但不能说明“晚间独立用户也更多”。
from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.globals import CurrentConfig
CurrentConfig.ONLINE_HOST = "assets/"
hours = ["18:00", "19:00", "20:00", "21:00"]
pv_values = [40, 38, 36, 34]
uv_values = [4, 4, 4, 4]
hourly_chart = (
Line(init_opts=opts.InitOpts(width="800px", height="420px"))
.add_xaxis(hours)
.add_yaxis(
"小时PV",
pv_values,
is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.extend_axis(
yaxis=opts.AxisOpts(
name="小时UV",
type_="value",
min_=0,
max_=6,
position="right",
)
)
.add_yaxis(
"小时UV",
uv_values,
yaxis_index=1,
is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="小时流量趋势"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
xaxis_opts=opts.AxisOpts(name="小时"),
yaxis_opts=opts.AxisOpts(name="小时PV", type_="value", min_=0, max_=45),
legend_opts=opts.LegendOpts(pos_top="8%"),
)
)
hourly_chart.render("hourly_traffic.html")
print("小时趋势图:2 条系列,4 个小时")小时趋势图:2 条系列,4 个小时在真实数据中,应先用 groupby('date')、groupby('hour') 聚合,再设置合适的轴范围。若两个指标量级相差很大且业务不要求逐时同步比较,也可以拆成两张单轴图,避免双轴刻度造成误读。
📝 动手练一练
改口径:把
daily_flow中的 UV 改成“点击次数不少于 2 次的用户数”,应如何调整?点击查看参考答案
可先按日期和用户统计点击次数,再筛选次数不少于 2 的用户:
per_user = click_df.groupby(["date", "user_id"]).size().reset_index(name="clicks") repeat_uv = ( per_user[per_user["clicks"] >= 2] .groupby("date")["user_id"] .nunique() .reset_index(name="repeat_uv") )这会得到“重复访问用户数”,与标准 UV 口径不同,展示时必须在标题或指标卡中明确命名。
避免误读:若营销活动当天 PV 翻倍但 UV 不增长,你会怎样向业务方解释?
点击查看参考答案
说明增长主要来自现有用户访问得更频繁,而不是触达人数扩大。下一步应继续拆分新老用户、渠道来源、停留时长和转化率,不能只凭 PV 峰值判定活动带来了更多新用户。
本章小结
本节先统一 PV、UV 口径,再用确定性事件数据完成日期和小时聚合,最后用双 Y 轴折线图比较不同量级的趋势。图表负责暴露模式,数据口径负责保证结论成立;两者缺一不可。
📋 行动清单
- 用
groupby独立计算日 PV、日 UV、小时 PV、小时 UV。 - 用
extend_axis与yaxis_index=1完成一张双 Y 轴折线图。 - 写出一条图表结论,并补充一条“这个结论不能证明什么”的边界说明。
—— 小象教研组

