在 Python 中使用 Elasticsearch(ES)进行数据可视化,核心流程是「ES 数据查询→结果解析为 DataFrame→用可视化库生成图表」。ES 负责高效聚合/筛选数据,Python 借助 Matplotlib/Seaborn(基础可视化)、Plotly(交互式可视化)、Pyecharts(中国式美观图表)等库,将数据转化为「趋势图、柱状图、饼图、热力图」等直观形式。以下是 4 类核心可视化场景 + 完整代码 + 优化技巧,覆盖从基础报表到交互式仪表盘的需求。
一、前置准备
1. 安装核心依赖库
# 基础依赖(ES 交互+数据处理+基础可视化)
pip install elasticsearch pandas matplotlib seaborn
# 可选依赖(交互式/美观图表)
pip install plotly pyecharts openpyxl
2. 基础配置(ES 连接+数据准备)
假设已完成 ES 索引创建(如电商订单索引 orders)和数据预处理,先通过 Python 连接 ES 并获取分析数据(示例:近30天订单数据):
from elasticsearch import Elasticsearch
import pandas as pd
from dotenv import load_dotenv
import os
# 加载环境变量(ES 地址、账号密码)
load_dotenv()
# 连接 ES
es = Elasticsearch(
os.getenv("ES_URL", "http://localhost:9200"),
basic_auth=(os.getenv("ES_USER", "elastic"), os.getenv("ES_PWD", "your-password"))
)
# 定义 ES 查询(近30天已支付订单,按城市/日期/分类聚合)
def get_es_analysis_data():
# 1. 按城市分组(销量排名)
city_query = {
"size": 0,
"query": {"bool": {"filter": [{"term": {"status": "paid"}}, {"range": {"pay_time": {"gte": "now-30d"}}}]}},
"aggs": {"city_group": {"terms": {"field": "city", "size": 10}, "aggs": {"total_amount": {"sum": {"field": "amount"}}}}}
}
city_response = es.search(index="orders", body=city_query)
city_data = [(b["key"], b["total_amount"]["value"]) for b in city_response["aggregations"]["city_group"]["buckets"]]
city_df = pd.DataFrame(city_data, columns=["城市", "总金额(元)"])
# 2. 按天分组(趋势分析)
trend_query = {
"size": 0,
"query": {"bool": {"filter": [{"term": {"status": "paid"}}, {"range": {"pay_time": {"gte": "now-30d"}}}]}},
"aggs": {"daily_trend": {"date_histogram": {"field": "pay_time", "calendar_interval": "day", "format": "yyyy-MM-dd"}, "aggs": {"order_count": {"count": {}}}}}
}
trend_response = es.search(index="orders", body=trend_query)
trend_data = [(b["key_as_string"], b["order_count"]["value"]) for b in trend_response["aggregations"]["daily_trend"]["buckets"]]
trend_df = pd.DataFrame(trend_data, columns=["日期", "订单数"])
# 3. 按商品分类分组(占比分析)
category_query = {
"size": 0,
"query": {"bool": {"filter": [{"term": {"status": "paid"}}, {"range": {"pay_time": {"gte": "now-30d"}}}]}},
"aggs": {"category_group": {"terms": {"field": "category", "size": 8}, "aggs": {"order_count": {"count": {}}}}}
}
category_response = es.search(index="orders", body=category_query)
category_data = [(b["key"], b["order_count"]["value"]) for b in category_response["aggregations"]["category_group"]["buckets"]]
category_df = pd.DataFrame(category_data, columns=["商品分类", "订单数"])
return city_df, trend_df, category_df
# 获取分析数据
city_df, trend_df, category_df = get_es_analysis_data()
print("✅ 数据获取完成")
print("城市销量数据:\n", city_df.head())
print("每日趋势数据:\n", trend_df.head())
print("商品分类数据:\n", category_df.head())
二、核心可视化场景(基础+进阶)
场景 1:基础可视化(Matplotlib/Seaborn)
适合快速生成静态图表(如报表附件、论文图表),风格简洁、易定制。
1.1 柱状图(城市销量排名 TOP10)
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文显示+图表风格
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows:SimHei,Mac:Arial Unicode MS
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid") # 白色网格风格
# 创建图表
plt.figure(figsize=(12, 6))
# 绘制柱状图(按总金额降序)
city_df_sorted = city_df.sort_values("总金额(元)", ascending=False)
sns.barplot(x="城市", y="总金额(元)", data=city_df_sorted, palette="viridis")
# 美化图表
plt.title("近30天各城市订单总金额TOP10", fontsize=14, pad=20)
plt.xlabel("城市", fontsize=12)
plt.ylabel("总金额(元)", fontsize=12)
plt.xticks(rotation=45) # 城市名称旋转45度,避免重叠
plt.grid(axis='y', alpha=0.3) # 横向网格线(透明度0.3)
# 标注数值(在柱子顶部显示金额)
for i, v in enumerate(city_df_sorted["总金额(元)"]):
plt.text(i, v + max(city_df_sorted["总金额(元)"]) * 0.01, f"{round(v, 2)}", ha='center', fontsize=10)
# 保存图表(高清无白边)
plt.tight_layout()
plt.savefig("城市销量排名.png", dpi=300, bbox_inches='tight')
plt.show()
1.2 折线图(每日订单趋势)
plt.figure(figsize=(14, 6))
# 绘制折线图(带标记点)
sns.lineplot(x="日期", y="订单数", data=trend_df, color="#2E86AB", linewidth=2, marker="o", markersize=6)
# 美化图表
plt.title("近30天每日订单数趋势", fontsize=14, pad=20)
plt.xlabel("日期", fontsize=12)
plt.ylabel("订单数", fontsize=12)
plt.xticks(rotation=60) # 日期旋转60度
plt.grid(alpha=0.3)
# 标注峰值(订单数最大的日期)
max_order_day = trend_df.loc[trend_df["订单数"].idxmax()]
plt.annotate(
f'峰值:{max_order_day["订单数"]}单',
xy=(max_order_day["日期"], max_order_day["订单数"]),
xytext=(max_order_day["日期"], max_order_day["订单数"] + 5),
ha='center',
arrowprops=dict(arrowstyle='->', color='red')
)
plt.tight_layout()
plt.savefig("每日订单趋势.png", dpi=300, bbox_inches='tight')
plt.show()
1.3 饼图(商品分类占比)
plt.figure(figsize=(10, 10))
# 绘制饼图(带百分比)
colors = sns.color_palette("Set3") # 配色方案
wedges, texts, autotexts = plt.pie(
category_df["订单数"],
labels=category_df["商品分类"],
autopct='%1.1f%%', # 百分比保留1位小数
colors=colors,
startangle=90, # 起始角度90度(垂直方向)
explode=[0.05] * len(category_df) # 每个扇形向外偏移5%,增强立体感
)
# 美化文字
plt.setp(texts, fontsize=12)
plt.setp(autotexts, fontsize=11, color="white", weight="bold")
plt.title("近30天各商品分类订单占比", fontsize=14, pad=20)
plt.axis('equal') # 保证饼图为正圆形
plt.tight_layout()
plt.savefig("商品分类占比.png", dpi=300, bbox_inches='tight')
plt.show()
场景 2:交互式可视化(Plotly)
适合生成可交互图表(如网页仪表盘),支持缩放、悬停显示详情、下载图片,体验更优。
2.1 交互式柱状图(城市销量)
import plotly.express as px
# 绘制交互式柱状图
fig = px.bar(
city_df_sorted,
x="城市",
y="总金额(元)",
title="近30天各城市订单总金额TOP10",
color="总金额(元)", # 按金额着色(渐变)
color_continuous_scale="viridis", # 渐变配色
text="总金额(元)" # 柱子顶部显示金额
)
# 美化配置
fig.update_layout(
xaxis_title="城市",
yaxis_title="总金额(元)",
xaxis_tickangle=-45, # 城市名称旋转-45度
template="plotly_white", # 白色模板
coloraxis_showscale=False # 隐藏颜色条(无需重复显示)
)
# 优化数值显示(保留2位小数)
fig.update_traces(
texttemplate='%{text:.2f}',
textposition='outside' # 数值显示在柱子外部
)
# 显示图表(自动打开浏览器)
fig.show()
# 保存为HTML文件(可嵌入网页)
fig.write_html("交互式城市销量排名.html")
2.2 交互式折线图(每日趋势)
fig = px.line(
trend_df,
x="日期",
y="订单数",
title="近30天每日订单数趋势",
markers=True, # 显示标记点
color_discrete_sequence=["#2E86AB"] # 线条颜色
)
# 美化配置
fig.update_layout(
xaxis_title="日期",
yaxis_title="订单数",
xaxis_tickangle=-60,
template="plotly_white",
hovermode="x unified" # 悬停时显示同一日期的所有数据
)
# 显示峰值标注
max_order_day = trend_df.loc[trend_df["订单数"].idxmax()]
fig.add_annotation(
x=max_order_day["日期"],
y=max_order_day["订单数"],
text=f'峰值:{max_order_day["订单数"]}单',
showarrow=True,
arrowhead=1,
arrowcolor="red"
)
fig.show()
fig.write_html("交互式每日订单趋势.html")
场景 3:中国式美观图表(Pyecharts)
适合生成符合国内审美习惯的图表(如政务报表、企业汇报),支持动态效果和丰富组件。
3.1 柱状图(城市销量排名)
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
# 准备数据(Pyecharts 要求格式:[(城市1, 金额1), (城市2, 金额2)])
city_data_pye = list(zip(city_df_sorted["城市"], city_df_sorted["总金额(元)"].round(2)))
# 创建柱状图(指定主题:明亮风格)
bar = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="1200px", height="600px"))
.add_xaxis([x[0] for x in city_data_pye])
.add_yaxis("总金额(元)", [x[1] for x in city_data_pye], itemstyle_opts=opts.ItemStyleOpts(color="#4CAF50"))
.set_global_opts(
title_opts=opts.TitleOpts(title="近30天各城市订单总金额TOP10", subtitle="数据来源:Elasticsearch", pos_left="center"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-45)),
yaxis_opts=opts.AxisOpts(name="总金额(元)"),
legend_opts=opts.LegendOpts(pos_bottom="5%"),
)
.set_series_opts(
label_opts=opts.LabelOpts(is_show=True, position="top", formatter="{c}"), # 顶部显示数值
markpoint_opts=opts.MarkPointOpts(
data=[opts.MarkPointItem(type_="max", name="最大值"), opts.MarkPointItem(type_="min", name="最小值")]
)
)
)
# 保存为HTML文件
bar.render("Pyecharts城市销量排名.html")
print("✅ Pyecharts图表已保存为 HTML 文件")
3.2 饼图(商品分类占比)
from pyecharts.charts import Pie
# 准备数据
category_data_pye = list(zip(category_df["商品分类"], category_df["订单数"]))
# 创建饼图
pie = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="1000px", height="800px"))
.add(
series_name="订单数",
data_pair=category_data_pye,
radius=["30%", "75%"], # 内半径30%,外半径75%(环形饼图)
center=["50%", "50%"], # 居中显示
rosetype="radius" # 玫瑰图样式(扇形大小随数值变化)
)
.set_global_opts(
title_opts=opts.TitleOpts(title="近30天商品分类订单占比", pos_left="center"),
legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%") # 图例垂直显示在左侧
)
.set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c} ({d}%)") # 显示:分类名+数量+百分比
)
)
pie.render("Pyecharts商品分类占比.html")
场景 4:多图表仪表盘(子图组合)
将多个图表组合为一个仪表盘,适合综合展示分析结果(如业务监控大屏)。
4.1 Matplotlib 子图组合
plt.figure(figsize=(20, 12))
# 子图1:城市销量柱状图(左上)
plt.subplot(2, 2, 1)
city_df_sorted_top5 = city_df_sorted.head(5) # 仅显示TOP5
sns.barplot(x="城市", y="总金额(元)", data=city_df_sorted_top5, palette="viridis")
plt.title("城市销量TOP5", fontsize=12)
plt.xlabel("")
plt.xticks(rotation=45)
for i, v in enumerate(city_df_sorted_top5["总金额(元)"]):
plt.text(i, v + max(city_df_sorted_top5["总金额(元)"]) * 0.01, f"{round(v, 2)}", ha='center', fontsize=9)
# 子图2:每日订单趋势折线图(右上)
plt.subplot(2, 2, 2)
sns.lineplot(x="日期", y="订单数", data=trend_df, color="#2E86AB", linewidth=2)
plt.title("每日订单趋势", fontsize=12)
plt.xlabel("")
plt.xticks(rotation=60)
# 子图3:商品分类饼图(左下)
plt.subplot(2, 2, 3)
plt.pie(category_df["订单数"], labels=category_df["商品分类"], autopct='%1.1f%%', colors=sns.color_palette("Set3"))
plt.title("商品分类占比", fontsize=12)
plt.axis('equal')
# 子图4:订单数分布直方图(右下)
plt.subplot(2, 2, 4)
sns.histplot(trend_df["订单数"], bins=10, kde=True, color="#A23B72") # kde:密度曲线
plt.title("订单数分布", fontsize=12)
plt.xlabel("订单数")
plt.ylabel("天数")
# 总标题
plt.suptitle("近30天电商订单数据分析仪表盘", fontsize=16, y=0.98)
plt.tight_layout()
plt.savefig("数据分析仪表盘.png", dpi=300, bbox_inches='tight')
plt.show()
4.2 Plotly 交互式仪表盘
import plotly.subplots as sp
# 创建2x2子图
fig = sp.make_subplots(
rows=2, cols=2,
subplot_titles=("城市销量TOP5", "每日订单趋势", "商品分类占比", "订单数分布"),
specs=[
[{"type": "bar"}, {"type": "scatter"}], # 第一行:柱状图+折线图
[{"type": "pie"}, {"type": "histogram"}] # 第二行:饼图+直方图
]
)
# 子图1:城市销量TOP5
city_top5 = city_df_sorted.head(5)
fig.add_trace(px.bar(city_top5, x="城市", y="总金额(元)").data[0], row=1, col=1)
# 子图2:每日订单趋势
fig.add_trace(px.line(trend_df, x="日期", y="订单数").data[0], row=1, col=2)
# 子图3:商品分类占比
fig.add_trace(px.pie(category_df, values="订单数", names="商品分类").data[0], row=2, col=1)
# 子图4:订单数分布
fig.add_trace(px.histogram(trend_df, x="订单数").data[0], row=2, col=2)
# 全局配置
fig.update_layout(
height=800, width=1200,
title_text="近30天电商订单数据分析仪表盘",
title_x=0.5,
template="plotly_white"
)
fig.show()
fig.write_html("交互式数据分析仪表盘.html")
三、可视化优化技巧(提升图表质感)
1. 配色方案选择
- 专业配色:
seaborn的viridis(蓝绿渐变)、plasma(紫橙渐变),适合数据对比; - 和谐配色:
Set2/Set3(多分类场景),避免颜色冲突; - 品牌配色:根据企业品牌色自定义(如
color="#1E40AF"深蓝色)。
2. 图表细节优化
- 标题:简洁明了(含时间范围+核心指标),字体大小14-16;
- 坐标轴:标签清晰,避免重叠(旋转角度45-60度),添加单位(如「元」「单」);
- 数值标注:重要图表添加数值标签,避免读者猜测;
- 网格线:仅保留横向网格线,透明度0.3-0.5(不干扰数据展示)。
3. 性能优化(大数据量场景)
- 数据采样:当 ES 返回数据量达10万+时,先采样(如取前1000条)再可视化;
- 分桶聚合:在 ES 中完成分桶(如按天/按城市),避免 Python 处理海量原始数据;
- 异步加载:Plotly/Pyecharts 生成的 HTML 图表,支持异步加载数据,提升打开速度。
4. 交互体验优化(交互式图表)
- 悬停效果:显示详细信息(如日期+订单数+总金额);
- 缩放/平移:支持鼠标缩放图表,查看局部细节;
- 下载功能:Plotly/Pyecharts 自带图片下载按钮,方便导出;
- 筛选功能:Plotly 支持添加下拉框/滑块,动态筛选数据(如按月份筛选)。
四、常见问题与避坑指南
-
中文乱码
- 原因:Matplotlib 默认不支持中文字体;
- 解决:设置
plt.rcParams['font.sans-serif'] = ['SimHei'](Windows)或['Arial Unicode MS'](Mac)。
-
图表保存后白边过多
- 解决:使用
plt.tight_layout()自动调整布局,保存时添加bbox_inches='tight'(去除白边)。
- 解决:使用
-
Plotly 图表无法显示
- 原因:Jupyter 环境未启用 Plotly 渲染器;
- 解决:在代码开头添加
import plotly.io as pio; pio.renderers.default='browser'(自动打开浏览器显示)。
-
数据量过大导致图表卡顿
- 解决:在 ES 中通过
size/from分页,或按时间/维度分桶,减少 Python 处理的数据量。
- 解决:在 ES 中通过
五、总结:可视化工具选择指南
| 工具 | 优势 | 适用场景 |
|---|---|---|
| Matplotlib/Seaborn | 轻量、灵活、定制性强 | 静态报表、论文图表、快速原型 |
| Plotly | 交互式强、支持网页嵌入、体验好 | 网页仪表盘、动态数据分析、分享展示 |
| Pyecharts | 中国式审美、动态效果丰富、文档友好 | 企业汇报、政务报表、国内业务场景 |
核心流程总结:
ES 聚合查询 → 数据解析为 DataFrame → 选择可视化工具 → 绘制图表 → 优化细节 → 保存/展示
关键建议:
- 优先在 ES 中完成数据筛选和聚合,减少 Python 数据处理压力;
- 静态图表用 Matplotlib/Seaborn,交互式图表用 Plotly,国内场景用 Pyecharts;
- 图表需「数据准确+逻辑清晰+美观易读」,避免过度装饰;
- 复杂仪表盘可结合 Flask/FastAPI 搭建网页服务,集成 Plotly/Pyecharts 图表实现实时刷新。
按以上场景和技巧,可覆盖 Python 中 90% 以上的 ES 数据可视化需求,从快速分析到企业级汇报均适用。


524

被折叠的 条评论
为什么被折叠?



