
上个月做了一个销售数据分析项目,甲方要求“图要好看,能直接放PPT”。
就这一个需求,我把手边能用的可视化库全试了一遍。踩了不少坑,也摸清楚了每个库的脾气。
Matplotlib是Python可视化的根,很多库底层都是它。
问题是默认画出来的图真的丑。我第一次用它交图给同事,同事直接问“这是Excel画的吗”。
其实只要换个主题,画风完全不一样:
importmatplotlib.pyplotasplt
importnumpyasnp
plt.style.use("seaborn-v0_8-whitegrid") # 换掉默认主题
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
sales = [12, 19, 15, 22, 18, 25]
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(months, sales, marker="o", linewidth=2.5, color="#2196F3", markersize=8)
ax.fill_between(range(len(months)), sales, alpha=0.1, color="#2196F3")
ax.set_title("上半年销售趋势", fontsize=16, fontweight="bold", pad=15)
ax.set_ylabel("销售额(万元)", fontsize=12)
ax.tick_params(labelsize=11)
plt.tight_layout()
plt.savefig("sales_trend.png", dpi=150, bbox_inches="tight")
plt.show()两个坑提前说:
一是中文显示方块,这个经典问题几乎每个新手都会碰,三行代码搞定:
importmatplotlib
# macOS
matplotlib.rcParams["font.family"] = "Arial Unicode MS"
# Windows
matplotlib.rcParams["font.family"] = "Microsoft YaHei"
# Linux(需要先安装字体)
matplotlib.rcParams["font.family"] = "WenQuanYi Micro Hei"二是plt.show()之后再plt.savefig(),存出来是空白图。顺序反过来,先save再show。我当初因为这个重跑了好几次脚本。

Plotly画出来的图是可以交互的——鼠标悬停有tooltip、可以缩放、可以隐藏/显示某条线。
做数据报告的时候特别有用,甲方自己就能探索数据,不用我在旁边一直操作演示。
importplotly.expressaspx
importpandasaspd
df = pd.DataFrame({
"月份": ["1月", "2月", "3月", "4月", "5月", "6月"],
"销售额": [120, 190, 150, 220, 180, 250],
"目标额": [150, 170, 160, 200, 200, 230],
})
fig = px.line(
df,
x="月份",
y=["销售额", "目标额"],
title="销售额 vs 目标额",
markers=True,
color_discrete_map={"销售额": "#2196F3", "目标额": "#FF9800"},
)
fig.update_layout(
font_family="Microsoft YaHei",
plot_bgcolor="white",
paper_bgcolor="white",
legend_title="指标",
)
fig.write_html("sales_report.html")
fig.show()有个细节要注意:导出HTML默认会把Plotly的JS打包进去,文件大概6MB,发给别人有点重。加一个参数就好:
fig.write_html("report.html", include_plotlyjs="cdn")
# 文件变成几十KB,需要联网加载JSPlotly Express写起来很顺,但碰到复杂图表要用plotly.graph_objects,那个学习曲线会陡一些,有心理准备。
Seaborn是基于Matplotlib的,专门做统计可视化,默认配色就比Matplotlib好看,分布图、相关性热力图、对比图用这个比较顺。
importseabornassns
importmatplotlib.pyplotasplt
importnumpyasnp
importpandasaspd
np.random.seed(42)
df = pd.DataFrame({
"部门": np.repeat(["销售部", "市场部", "技术部"], 50),
"月销售额": np.concatenate([
np.random.normal(15, 3, 50),
np.random.normal(12, 2, 50),
np.random.normal(8, 1.5, 50),
])
})
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
sns.boxplot(data=df, x="部门", y="月销售额", ax=axes[0], palette="Set2")
axes[0].set_title("各部门销售额分布", fontsize=14)
sns.violinplot(data=df, x="部门", y="月销售额", ax=axes[1], palette="Set2")
axes[1].set_title("各部门销售额分布(小提琴图)", fontsize=14)
plt.tight_layout()
plt.savefig("distribution.png", dpi=150, bbox_inches="tight")Seaborn 0.12之后有几个API改了,网上很多教程还是旧版写法,遇到警告别慌:
# 旧写法(会报DeprecationWarning)
sns.set(style="whitegrid")
# 新写法
sns.set_theme(style="whitegrid")还有distplot被废弃了,换成histplot或者kdeplot。不知道有多少人因为这个对着报错信息发呆过。
Pyecharts是百度ECharts的Python封装,画出来有商业报表的感觉,老板和甲方一眼就喜欢。
frompyecharts.chartsimportBar
frompyechartsimportoptionsasopts
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
sales = [120, 190, 150, 220, 180, 250]
target = [150, 170, 160, 200, 200, 230]
bar = (
Bar()
.add_xaxis(months)
.add_yaxis("实际销售额", sales, color="#2196F3")
.add_yaxis("目标额", target, color="#FF9800")
.set_global_opts(
title_opts=opts.TitleOpts(title="上半年销售完成情况"),
xaxis_opts=opts.AxisOpts(name="月份"),
yaxis_opts=opts.AxisOpts(name="金额(万元)"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
legend_opts=opts.LegendOpts(pos_top="5%"),
)
)
bar.render("sales_bar.html")有个限制要知道:Pyecharts只能导出HTML,想导出图片要装snapshot-selenium或者snapshot-phantomjs,配置很麻烦,而且经常出问题。我现在直接交HTML,截图让浏览器截,别在这上面浪费时间。
文档也是个坑:中英文两版,中文版更新慢,有时候某个参数对不上,要去看英文文档或者直接翻源码。
Altair基于Vega-Lite,写法是声明式的——描述“我要把哪列数据映射到哪个视觉通道上”,不用操心怎么画。
第一次用的时候有点不适应,但习惯了之后写起来思路很顺:
importaltairasalt
importpandasaspd
df = pd.DataFrame({
"月份": ["1月", "2月", "3月", "4月", "5月", "6月"],
"销售额": [120, 190, 150, 220, 180, 250],
"同比增长": [0.05, 0.12, -0.02, 0.15, 0.08, 0.18],
})
chart = (
alt.Chart(df)
.mark_bar()
.encode(
x=alt.X("月份:N", title="月份"),
y=alt.Y("销售额:Q", title="销售额(万元)"),
color=alt.condition(
alt.datum["同比增长"] >0,
alt.value("#2196F3"),
alt.value("#F44336"),
),
tooltip=["月份", "销售额", "同比增长"],
)
.properties(title="上半年销售额", width=500, height=300)
)
chart.save("sales_altair.html")两个要注意的:Altair默认只支持5000行数据,超了报错,加这一行:
alt.data_transformers.disable_max_rows()还有就是Altair在Jupyter里体验最好,普通Python脚本跑需要额外配置才能预览,不然只能导出HTML看,稍微不方便一点。
库 | 适合什么 | 导出格式 |
|---|---|---|
Matplotlib | 静态图,细节控制,论文图 | PNG / PDF / SVG |
Plotly | 交互图,数据探索 | HTML / PNG |
Seaborn | 统计分析,分布对比 | PNG / PDF |
Pyecharts | 商业报表,给非技术人员看 | HTML |
Altair | 声明式写法,Jupyter环境 | HTML / PNG |
我现在最常用的是Plotly和Pyecharts。Plotly自己探索数据用,Pyecharts做出来拿给甲方看比较顺眼,两个各有各的场合。
Matplotlib虽然丑,但还是要会。它是底层,有些特殊需求其他库搞不定的时候只有它能用。
你最近在用哪个?评论区聊聊。
“无他,惟手熟尔”!有需要的用起来!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!