上礼拜有个刚转行做数据分析的朋友问我:matplotlib我都还没学明白,怎么到处都在说seaborn?我给他打了个比方:matplotlib是原木,什么都能做,但所有事都得自己动手;seaborn是给你切好拼好的板材,专门用来做统计图形,又美又简单。这个标题里的六个字,其实是同一个原因造成的——它的底层替你完成了大量统计计算和视觉设计决策。这篇东西会把seaborn怎么用、为什么好用、哪些坑我在项目里踩过,一次讲清楚。适合刚从matplotlib过渡过来的同学,也适合那些统计图形需求密集、希望快速出图的数据分析从业者。
1. 为什么我从matplotlib迁到了seaborn:不是二选一,而是互补
1.1 matplotlib的定位决定了它的使用成本
先说个常被误解的点:matplotlib和seaborn不是竞争关系。matplotlib是Python绘图生态的事实底座,它负责画坐标系、处理刻度、渲染导出、交互事件,是一切二维绘图的底层引擎。seaborn是构建在matplotlib之上的高级封装,它最终调用的仍然是matplotlib的绘图接口。所以你装了seaborn,就一定带着matplotlib,这不冲突。
matplotlib最大的问题是:它太底层了。你想画一个漂亮的直方图,得自己算bins、自己调透明度、自己考虑颜色叠加;想画箱线图,还要自己算Q1、Q3、中位数、离群点边界;想画回归散点图,得先画散点、再拟合一条线、再铺置信区间。一次两次可以,但在探索性数据分析阶段,你每天要画几十张图,手工操作的成本就非常高了。尤其当你面对的是DataFrame这种结构化的宽表数据时,matplotlib的循环分组绘图代码会又臭又长,经常画着画着自己都不知道哪一组对应哪个颜色。
1.2 seaborn的底层逻辑:面向统计图形,而不是面向点线面
seaborn和matplotlib思考问题的方式完全不同。matplotlib的思路是“你给我点的坐标,我给你画点;你给我数组,我给你画线”。seaborn的思路是“你给我一个DataFrame,告诉我哪一列是x、哪一列是y、哪一列是分组变量,我来完成分组聚合、统计计算和视觉映射”。
举一个实际例子。用matplotlib画分组箱线图,你需要先把数据按组拆开,逐个计算箱线位置,再设置坐标轴标签。用seaborn只需要一行:
import seaborn as sns import matplotlib.pyplot as plt tips = sns.load_dataset("tips") sns.boxplot(data=tips, x="day", y="total_bill", hue="smoker") plt.show()这一行代码背后做了几件事:按星期四组、按是否吸烟两组做交叉分组;对每个子组计算四分位数和离群值;为每组生成一个箱体;自动生成图例;自动调整坐标轴标签。这些操作在matplotlib里自己实现,至少要二三十行,而且很容易在某个边界条件上报错。
1.3 统计图形的默认行为,比手工绘图更严谨
seaborn还有一个容易被忽视的价值:它在绘制统计图形时,默认会做统计推断。画柱状图时,它默认显示的是均值和自助法置信区间;画回归图时,它默认会画出置信带;画箱线图时,它默认按1.5倍IQR判断离群点。这些默认行为是一个统计学专业背景的开发者设定的,比普通用户自己手搓出来的图更可靠。
所以我的建议是:不要纠结“该学matplotlib还是seaborn”。两个都要会,但分工不同。快速探索数据、做统计图形、画分组对比图,用seaborn;复杂排版、自定义画布、精细调整每一个视觉元素,回到matplotlib。我的习惯是80%的探索性图表用seaborn生成,最后在发表的时候,再用matplotlib对重点图做局部定制。
2. 安装与第一张图:卡在seaborn库下载上的人真不少
2.1 最稳妥的安装方式与国内镜像
“seaborn库下载”这个热词能上热搜,说明很多人在安装环节就卡住了。实际上安装本身不复杂,复杂的是网络环境。最常规的安装方式是使用pip:
pip install seaborn或者使用conda:
conda install -c conda-forge seaborn国内网络环境下,pip默认源经常下载很慢或者超时。这时候别傻等,直接换成国内镜像源:
pip install seaborn -i https://pypi.tuna.tsinghua.edu.cn/simple清华源、阿里云源、豆瓣源都可用,我个人用清华源最多,稳定性和更新速度都比较好。装完之后验证一下版本:
import seaborn as sns print(sns.__version__)正常情况下会输出类似0.13.2这样的版本号。如果你看到的是0.11.x甚至更老,建议升级到新版本,因为老版本接口和现在差异很大,看新教程时会遇到各种报错。
2.2 内置数据集:联网才能用,离线替代方案
seaborn内置了几个经典数据集,比如tips(餐厅小费)、iris(鸢尾花)、titanic(泰坦尼克号乘客信息)、penguins(企鹅数据)。很多人照着教程敲sns.load_dataset("tips"),结果报错,原因是这个函数需要联网从GitHub拉取数据。解决方式有两种:一是确保网络畅通;二是干脆自己构造样本数据,或者加载本地CSV。
如果你用的是公司内网或者离线环境,我建议直接用pandas读本地文件:
import pandas as pd df = pd.read_csv("your_data.csv")自动动手构造一份模拟数据也是好办法,后面的实战部分我会给一份完整的构造例子。关键是理解sns.load_dataset只是验证seaborn功能用的,真正项目里你面对的一定是自己的数据。
2.3 第一张统计图:从中文字体坑说起
很多人的第一张seaborn图都会遇到同一个问题:图中中文全部变成小方块。这是因为matplotlib默认字体里没有中文字形。解决方案是在画图前设置中文字体:
plt.rcParams["font.sans-serif"] = ["SimHei"] # 也可以用 "Microsoft YaHei" plt.rcParams["axes.unicode_minus"] = False # 解决负号显示异常注意顺序:如果你后面调用了sns.set_theme(),它会把rcParams重置掉,字体设置会失效。所以正确做法是先调用sns.set_theme()设置整体风格,再设置中文字体。先跑一个最简单的图验证环境:
import seaborn as sns import matplotlib.pyplot as plt sns.set_theme(style="whitegrid") plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False tips = sns.load_dataset("tips") sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time") plt.title("小费金额与消费总额的关系") plt.show()这一张图跑通了,说明seaborn、matplotlib、中文字体三件事都到位了,接下来可以放心画各种图。
2.4 版本演进带来的接口变化
补充一个版本相关的坑。seaborn在0.11版本做了一次大的接口调整:老的distplot被拆分为histplot和kdeplot,很多老教程里的代码在新版本下会报警告甚至报错。如果你看的是2020年之前的教程,遇到distplot相关的报错,不要慌,把函数名换成histplot或者kdeplot即可。新版seaborn在0.12、0.13等版本中持续优化了set_theme的图形主题,整体出图效果比老版好看了不少,建议直接用新版本。
3. 分类数据的三种可视化层次:单列、双列分组、多列分层
分类数据可视化是seaborn最擅长的领域,也是我日常用得最多的功能。按复杂程度,我习惯把分类图拆成三个层次:只看单一类别分布的单列分析、对比两个类别维度差异的双列分组、以及引入更多语义映射的多列分层。
3.1 柱状图:默认的统计逻辑可能和你想的不一样
sns.barplot看起来和matplotlib的plt.bar差不多,但统计逻辑完全不同。matplotlib的plt.bar画的是你给定的数值;seaborn的barplot默认画的是每个分组的均值,并自动加上基于自助法计算的置信区间误差棒。
sns.barplot(data=tips, x="day", y="total_bill", hue="sex")这里如果不习惯,很容易误解:为什么柱子的高度不是原始数据的和?因为seaborn默认用estimator="mean"做估计。如果你想显示总量,改成sns.barplot(..., estimator=sum);想显示中位数,改成estimator="median"。误差棒的类型通过errorbar控制,新版默认是("ci", 95),也就是95%置信区间,也可以传errorbar="sd"显示标准差。
柱状图适合展示一组分类变量的中心趋势,但有个明显的缺陷:它把原始分布信息压缩成了一个点。数据不满足正态分布,或者存在离群点时,均值会失真。所以我看数据时,柱状图一般只用作快速预览,正式分析还会配合箱线图或小提琴图。
3.2 箱线图和小提琴图:用来看分布,而不是看均值
箱线图是统计分析的标准配置。seaborn的箱线图遵循经典的定义:箱体范围是Q1到Q3,中间线是中位数,胡须延伸至1.5倍IQR范围内最远的数据点,超过这个范围的点单独显示为离群点。
sns.boxplot(data=tips, x="day", y="total_bill")因为箱线图能同时展示四分位范围、中位数和离群点,对比多个组之间的分布差异时非常直观。比如下面这张图,你能一眼看出周五的消费金额分布比较集中,而周六、周日的中位数更高且分布更宽。
箱线图的缺点是:当分布出现双峰或者奇怪形态时,箱线图丢失了这些信息,因为你只看得到分位数。violinplot可以弥补这一点——它把小提琴形状横过来,其实就是旋转后的核密度估计图,能看到完整的分布形态:
sns.violinplot(data=tips, x="day", y="total_bill", hue="smoker", split=True)注意这个split=True参数,它只对hue有两个水平时有效,作用是把一个小提琴从中间劈开,左侧显示一个类别的密度,右侧显示另一个类别,节省横向空间,对比也方便。简单来说:想严谨比较中位数和离群值用箱线图,想看清分布形态用提琴图。
3.3 散点抖动图:把原始数据也画出来
箱线图和提琴图展示的是统计汇总,但数据量不大时,把原始数据点也画出来更有说服力。seaborn有两个选择:stripplot和swarmplot。
sns.stripplot(data=tips, x="day", y="total_bill", jitter=0.2, alpha=0.5) sns.swarmplot(data=tips, x="day", y="total_bill", hue="sex", dodge=True)stripplot的特点是给每个点一个小的随机抖动避免完全重叠,实现简单,数据量大时也扛得住。swarmplot则是通过迭代算法,让每个点与邻近点保持不重叠,视觉上非常整齐,点与点像蜜蜂群一样排列。但swarmplot的算法复杂度较高,数据点超过几百个时会非常慢,这时候还是用stripplot配合透明度更实际。
3.4 hue、size、style三个映射通道
seaborn分组能力强,核心在于它有多个语义映射通道。hue把颜色通道映射到类别变量,size把点的大小映射到数值或类别变量,style把点或线的样式映射到变量。以scatterplot为例:
sns.scatterplot( data=tips, x="total_bill", y="tip", hue="day", size="size", style="smoker" )这一行代码就在一个散点图里同时编码了三个维度:点的颜色代表星期几,点的大小代表用餐人数,点的形状代表是否吸烟。这种多通道映射是seaborn区别于普通绘图库的重要特性,它让你能在二维平面上显示更多维度的信息。
但使用hue时要克制。类别水平太多时,比如超过十个,颜色会难以区分,图例也会占掉一大块区域。我的经验是一个图最多编码4个维度,hue色块数量控制在8个以内。
4. 分布、相关性和趋势:从单变量到多变量的一站式探测
分类图解决的是“组间差异”问题,但数据分析里更大的需求是理解变量本身的分布、变量之间的关系、以及随时间或连续变量的变化趋势。这三类需求seaborn都有对应的图形。
4.1 直方图与核密度估计:histplot和kdeplot的正确打开方式
新版seaborn把直方图入口统一为histplot,它取代了老版本的distplot。最基础的用法:
sns.histplot(data=tips, x="total_bill", bins=30, kde=True)bins控制分箱数量,这个参数选择直接影响图的形态:bins太少,分布细节被掩盖;bins太多,又会出现大量空箱噪声。我的经验是先使用默认值,再尝试20、40、60,挑一个既能看出分布趋势又不显得碎的值。kde=True会在直方图上叠加一条平滑的核密度曲线,方便观察概率密度走势。
如果你想只看密度曲线,用kdeplot:
sns.kdeplot(data=tips, x="total_bill", hue="time", fill=True, alpha=0.4)这里hue="time"可以让不同组的密度曲线分别绘制,fill=True给每个密度区域填充颜色,再配合alpha控制透明度。对比多个组的分布形态,这种方式比重叠直方图更清晰,因为没有分箱带来的离散噪声,曲线更平滑。
histplot和kdeplot还有一个好用的小参数:stat="density"可以让纵轴显示概率密度而不是频数,当多组数据样本量不一致时,用密度而不是频数对比才公平。
4.2 jointplot:两张图看相关性
jointplot把散点图和边缘分布结合起来:中间是两变量的散点图,上边和右边分别是对应变量的直方图或核密度曲线。这样你既能看出两变量之间的相关趋势,又能同时看到各自分布的形态。
sns.jointplot(data=tips, x="total_bill", y="tip", kind="scatter")kind参数可以切换不同的图形类型:hex用得最多,数据量巨大时用六边形分箱比散点更清晰;kde显示二维密度等高线,适合看分布密度高的区域;reg会在散点基础上加回归线和置信带,快速判断线性趋势的方向和强度。
sns.jointplot(data=tips, x="total_bill", y="tip", kind="reg")在探索阶段,我经常用jointplot快速判断任意两个数值变量之间的相关形态,不一定非要用皮尔逊相关系数。因为相关系数只能衡量线性关系,两个明显非线性相关的变量,相关系数可能接近0,但图上一看就明白了。
4.3 pairplot:批量探索数据的利器
拿到一份数据,还不知道哪些变量之间有关系时,pairplot是最佳起点。它会把DataFrame里所有数值列两两组合,生成一个矩阵图:对角线位置是每个变量的直方图,非对角线位置是两两散点图。
sns.pairplot(tips, hue="sex")传入hue参数后,所有散点会根据颜色分组,对角线的分布图也会按组分别绘制。这样你一次能看到所有数值列两两之间的关系,以及组间差异。探索性数据分析阶段,这一张图的信息量顶得上看几十张独立图表。
但pairplot有两个局限:一是列数太多时生成的图会非常宽,超过8个数值变量就不太适合了,所以大批量变量时建议先筛选或分组再看;二是数据量很大时绘制速度比较慢,建议先用df.sample(500)抽样再画。
4.4 heatmap:相关性矩阵的最直观表达
相关性分析是数值变量探索的收尾动作。先用pandas算出相关性矩阵:
num_cols = tips.select_dtypes(include="number").columns corr = tips[num_cols].corr() sns.heatmap(corr, annot=True, cmap="RdBu_r", center=0, vmin=-1, vmax=1)几个参数说明一下:annot=True在格子里显示数值;cmap="RdBu_r"使用红蓝发散色板,正的用红色偏暖,负的用蓝色偏冷;center=0让色板以0为中心对称;vmin=-1和vmax=1固定色板范围,因为相关系数的取值范围就是负一到正一,不固定的话不同图的颜色刻度不一致,没法横向比较。
heatmap还能用来画其他矩阵,比如分组交叉表、混淆矩阵、缺失值分布。它的本质是把矩阵数值映射为颜色,只要数据是二维表格结构,都可以用。
5. 更美的关键不在画图,而在set_theme与调色板设置
有些人觉得seaborn默认图好看,有些人觉得也就那样。其实seaborn的美不是某个图形的功劳,而是一套全局视觉系统的功劳。理解set_theme和调色板,你就掌握了seaborn丑图变美的钥匙。
5.1 set_theme到底干了什么
sns.set_theme()是seaborn的全局配置入口,一次性设置背景风格、调色板、字体大小、坐标轴颜色、网格线样式等几十项rcParams参数。以前老版本要分别调用set_style、set_palette、set_context,现在一个函数全搞定。
sns.set_theme( style="whitegrid", palette="pastel", font="SimHei", rc={"figure.dpi": 120, "axes.titlesize": 14} )style参数有五个可选值:whitegrid适合统计图形,白色背景加浅色网格线,数据点对比清晰;darkgrid适合深色背景的演示场景;white干净简洁,适合要发布到论文里的图;dark适合做大屏展示;ticks则只有刻度线不加网格。我日常用whitegrid最多,正式论文图用white。
关键点是,set_theme是全局的,一次设置,之后所有图都套用这套风格。所以别每张图单独调,先定好整体调子,画完再对个别图做微调。
5.2 调色板:颜色不是玄学,是有设计逻辑的
seaborn的调色板系统很讲究。先记住一个函数sns.color_palette,它返回一组颜色列表,几乎所有的调色板都从它派生。
最常用的几类:
# 命名色板:deep、muted、bright、pastel、dark、colorblind sns.color_palette("deep", 8) sns.color_palette("colorblind", 10) # 连续色板 sns.color_palette("viridis", 20) sns.color_palette("flare", 20) # 发散色板 sns.diverging_palette(240, 0, n=9)命名色板里,deep饱和度高、适合印刷和展示;muted饱和度降低、柔和耐看,适合PPT;pastel再低一点,适合大面积填充;colorblind专门为色觉障碍人群设计,蓝和橙的区分度明显,做公开报告时尽量用这一组。
在绘图时,直接把色板名称传给palette参数:
sns.boxplot(data=tips, x="day", y="total_bill", hue="smoker", palette="Set2")这里透传的palette也可以是一个具体的颜色列表,比如palette=["#4C72B0", "#DD8452"],这在公司VI色需要统一时会用到。
补充一个非常推荐的发散色板用法:画连续数值的分组时,light_palette("seagreen", reverse=True)会生成从浅绿到深绿的渐变,适合表达强度排序。而diverging_palette(240, 0, n=9)生成蓝到红的对称渐变,适合画温度、收益等有正有负的指标。
5.3 字体、图例、坐标轴:细节微调还是要回到matplotlib
seaborn负责把图和统计做完,但到了“让这张图切实能放进报告里”的阶段,你还是需要一些matplotlib的细调手段:
fig, ax = plt.subplots(figsize=(10, 6)) sns.boxplot(data=tips, x="day", y="total_bill", ax=ax) ax.set_title("每日消费金额分布", fontsize=16) ax.set_xlabel("星期", fontsize=13) ax.set_ylabel("消费金额", fontsize=13) ax.legend(title="是否吸烟") plt.xticks(rotation=30, ha="right") plt.tight_layout()这里有个关键认知:seaborn的每个绘图函数都接受ax参数,它把图画在指定的matplotlib坐标轴上。画完之后,这个坐标轴的标题、标签、图例、刻度全部可以用matplotlib原生的API去改。所以不要觉得用了seaborn就丧失了定制能力,你只是少写了那些重复造轮子的统计代码,视觉级的控制权一直都在。
遇到图例位置不合适的,直接ax.legend(loc="upper left")调整;坐标轴刻度太密的,用ax.set_xticks手动指定。这些matplotlib的精细化操作,在seaborn图里同样适用。
6. 实战:用一份自建销售数据把前面的知识点串起来
前几节讲了seaborn的核心图形和配置,我把它们组织成一个完整分析流程。用一个模拟的连锁奶茶门店经营数据来做演示,全程不需要联网,复制即用。
6.1 构造模拟数据
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_theme(style="whitegrid") plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False rng = np.random.default_rng(42) areas = ["城东店", "城西店", "城南店", "城北店"] days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] items = ["珍珠奶茶", "冰美式", "鲜果茶", "抹茶拿铁"] df = pd.DataFrame({ "门店": rng.choice(areas, 1000), "星期": rng.choice(days, 1000), "品类": rng.choice(items, 1000), "销量": rng.integers(30, 200, 1000), "单价": rng.choice([12, 15, 18, 22], 1000), "平均等待分钟": rng.integers(3, 15, 1000), }) df["营业额"] = df["销量"] * df["单价"]这份数据有1000条记录,模拟了四个门店、一周七天、四个品类的销售情况,还带了一个服务效率指标。虽然数据是模拟的,但字段结构和真实业务数据非常接近,分析流程可以直接迁移。
6.2 第一张图:分组柱状图看整体格局
先看整体哪个品类贡献了最多营业额,以及门店之间的差异:
plt.figure(figsize=(10, 6)) sns.barplot(data=df, x="品类", y="营业额", hue="门店", estimator="median", errorbar=("ci", 95)) plt.title("不同品类在各门店的营业额中位数对比") plt.legend(title="门店", bbox_to_anchor=(1.05, 1), loc="upper left") plt.tight_layout()这张图用了柱状图最核心的能力:x="品类"进行分组,hue="门店"再做一层细分,estimator="median"把默认的均值改成中位数,减少离群值影响。从图中我们可以快速判断:不同品类的营业额基准差异、各门店在每个品类上的相对表现、以及置信区间宽度反映的样本稳定性。如果某个门店的误差棒特别长,说明销量波动大,值得进一步排查。
6.3 第二张图:箱线图看星期波动
接下来看一个星期规律。星期几是分类变量,销量是连续变量,最佳选择是箱线图:
plt.figure(figsize=(10, 6)) sns.boxplot(data=df, x="星期", y="销量", hue="品类", palette="Set3") plt.title("一周七天各品类销量分布") plt.xticks(rotation=30, ha="right") plt.tight_layout()这里有一个容易踩的坑:把星期当作字符串时,seaborn会按字母顺序排序,周一的英文首字母是M,周二是T,结果画出来的x轴顺序是乱的。解决方法是把星期列转成分类类型并指定顺序:
day_order = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] df["星期"] = pd.Categorical(df["星期"], categories=day_order, ordered=True)转换之后再画图,x轴就会按业务习惯排序,这张图能看出周末销量是否有明显抬升,哪个品类是周末的爆款。
如果觉得箱线图还不够直观,还可以叠加一层swarmplot显示原始数据:
plt.figure(figsize=(10, 6)) sns.violinplot(data=df, x="星期", y="销量", hue="品类", split=False, palette="Pastel1") sns.stripplot(data=df, x="星期", y="销量", hue="品类", size=2, alpha=0.3, dodge=True, legend=False) plt.title("销量分布:小提琴图叠加原始散点") plt.tight_layout()小提琴图展示了分布的完整形态,叠加的散点让读者知道样本量大概是多少。注意第二条stripplot要加legend=False,否则图例会重复。
6.4 第三张图:散点图看相关关系
业务上经常想验证一个问题:排队等得越久,销量是不是越差?画出平均等待分钟和销量的关系:
sns.lmplot(data=df, x="平均等待分钟", y="销量", hue="门店", markers=["o", "s", "D", "^"], height=6) plt.title("等待时间与销量关系:各门店回归对比")lmplot是在scatterplot基础上加了回归线和置信带的组合图。这里用hue="门店"把四个门店拆成四组,每组单独拟合一条回归线。从图上就能看出,是否存在普遍的负相关趋势,以及哪个门店的斜率特别陡。markers参数给每组不同的点样式,因为当你把图打印成黑白版本时,只靠颜色区分组别是不可靠的。
6.5 第四张图:相关矩阵收尾
最后把数值变量全部放进相关性矩阵,避免遗漏隐性关系:
num_cols = df.select_dtypes(include=np.number).columns corr = df[num_cols].corr() plt.figure(figsize=(8, 6)) sns.heatmap(corr, annot=True, cmap=sns.diverging_palette(240, 10, sep=20), center=0, square=True) plt.title("销售数据数值变量相关性矩阵") plt.tight_layout()select_dtypes(include=np.number)这个细节一定不能省。pandas的DataFrame里如果混入了文本列,直接调用df.corr()会报错或者忽略文本列,提前筛选数值列干净利落。square=True让每个格子都是正方形,整体视觉更均衡。
相关性矩阵能看到几个重点:营业额和销量之间必然高度正相关,因为营业额等于销量乘单价;等待分钟和销量可能是负相关,说明服务效率影响购买意愿;单价和销量之间可能是负相关,高单价导致低销量。这些隐藏在数据里的关系,用一张热图就能快速识别。
6.6 批量导出图片
分析做完,把图汇总导出。
figures = [plt.figure(num) for num in plt.get_fignums()] for i, fig in enumerate(figures, 1): fig.savefig(f"report_plot_{i}.png", dpi=300, bbox_inches="tight", facecolor="white")bbox_inches="tight"可以帮助避免坐标轴标签被裁掉;dpi=300适合打印或正式报告。如果你要把多张图拼在一起做汇报,也可以用matplotlib的subplots手动排版,但seaborn图存成文件后放到PPT里,最后再用PPT排布,操作起来更灵活。
最后说点个人体会。我最早也嫌弃seaborn“太难定制”,总觉得一行sns.scatterplot出来的图没有自己手搓的好看。后来项目多了才想明白:它那套默认设计是一整套美学,包括坐标轴、间距、颜色、字体比例,整体调性好。你只替换其中个别元素,不会破坏整体效果;但你从零手搓,往往要调半天还不协调。我现在习惯是先sns.set_theme()把所有图整体定调,再只针对重点图做局部修饰。如果你正在从matplotlib往seaborn过渡,建议先别着急定制,连用两周默认效果之后再做微调,到时候你会清楚地知道到底该调哪里。