Python数据可视化:使用Seaborn绘制山脊图(Ridge Plot)详解
本文详细介绍如何使用Python的Seaborn库绘制山脊图(Ridge Plot)。通过Netflix电影数据示例,逐步演示如何优化FacetGrid参数、处理重叠区域及自定义样式,最终实现类似Joy Division专辑封面的可视化效果,适用于数据分布对比分析。
1. 引言
山脊图由垂直堆叠的折线图构成,各折线下的区域相互重叠,并共享同一个x轴。

这种图表形式相对少见,但因其紧凑且引人注目的视觉效果而备受青睐。正如Ridge plot是所暗示的,该图表外观酷似山脊,因此得名。此外,它也被称为Joy Plots,源于Joy Division乐队在其专辑封面中使用了这种可视化形式。

2. 举个栗子
了解背景后,我们通过一个具体案例进行演示。使用的数据集主要包含Netflix 的作品及其对应的IMDB 评分。
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
df = pd.read_csv('./data/film.csv')
languages = ['English', 'Hindi', 'Spanish',
'French', 'Italian', 'Portuguese']
df_filtered = df[df['Language'].isin(languages)]
df_filtered运行结果如下:

上表从左至右依次显示:ID、电影名称、电影类型、首映日期、电影时长、IMDB评分以及电影语种。
首先,我们利用Seaborns FacetGrid库为每种语言类别的电影创建不同IMDB评分下的概率密度分布曲线。实现这一功能十分简单,只需对数据表中相应的名称字段按值进行分组统计即可。
代码如下:
sns.set_theme(style="white")
g = sns.FacetGrid(df_filtered, row="Language")
g.map_dataframe(sns.kdeplot, x="IMDB Score")
g.set(ylabel="")结果如下:

上述实现使用了默认参数配置。横轴表示IMDB评分,纵轴表示不同语种电影在特定IMDB得分下的概率。虽然图例展示了单个语种电影评分的概率密度分布,但难以直观对比不同语种间的分布差异。
接下来,我们尝试改进显示效果,通过调整FacetGrid函数中的相应参数,使图表变得更宽更短。
代码如下:
sns.set_theme(style="white")
g = sns.FacetGrid(df_filtered, row="Language", aspect=9, height=1.2)
g.map_dataframe(sns.kdeplot, x="IMDB Score")
g.set(ylabel="")结果如下:

尽管上述改进使数据对比更加明显,但从视觉效果来看,该可视化图表仍缺乏足够的吸引力。
观察上图可知,大多数人并不关注左侧的Y轴信息,而是更关注数据的形状。因此,我们可以删除Y轴。
代码如下:
sns.set_theme(style="white")
g = sns.FacetGrid(df_filtered, row="Language", aspect=9, height=1.2)
g.map_dataframe(sns.kdeplot, x="IMDB Score")
g.set_titles("")
g.set(yticks=[],ylabel="")
g.despine(left=True)运行结果如下:

3.山脊图
经过上述优化,不同语种电影的IMDB评分概率密度分布依然不够直观。接下来,我们将逐步介绍最终解决方案——山脊图。
首先,我们需要确保背景透明。
sns.set_theme(style="white", rc={"axes.facecolor": (0, 0, 0, 0)})接着,我们需要填充线条内部的区域。
g.map_dataframe(sns.kdeplot, x="IMDB Score", fill=True, alpha=1)执行上述操作后,不同语种间的区域会出现重叠,此时还需要对重叠部分进行区分。
我们通过以下代码进行区分:
sns.set_theme(style="white", rc={"axes.facecolor": (0, 0, 0, 0)})
g = sns.FacetGrid(df_filtered, row="Language", aspect=9, height=1.2)
g.map_dataframe(sns.kdeplot, x="IMDB Score", fill=True, alpha=1)
g.map_dataframe(sns.kdeplot, x="IMDB Score", color='black')
g.fig.subplots_adjust(hspace=-.5)
g.set_titles("")
g.set(yticks=[])
g.despine(left=True)运行结果如下:

至此,我们实现了第一版山脊图,随后可根据需求进行自定义扩展。FacetGrid函数非常适合创建多个可视化图例,而.map和.map_dataframe 方法则允许我们与所有子图进行交互。
代码如下:
sns.set_theme(style="white", rc={"axes.facecolor": (0, 0, 0, 0), 'axes.linewidth':2})
palette = sns.color_palette("Set2", 12)
g = sns.FacetGrid(df_filtered, palette=palette, row="Language", hue="Language", aspect=9, height=1.2)
g.map_dataframe(sns.kdeplot, x="IMDB Score", fill=True, alpha=1)
g.map_dataframe(sns.kdeplot, x="IMDB Score", color='black')
def label(x, color, label):
ax = plt.gca()
ax.text(0, .2, label, color='black', fontsize=13,
ha="left", va="center", transform=ax.transAxes)
g.map(label, "Language")
g.fig.subplots_adjust(hspace=-.5)
g.set_titles("")
g.set(yticks=[], xlabel="IMDB Score")
g.despine( left=True)
plt.suptitle('Netflix Originals - IMDB Scores by Language', y=0.98)运行结果如下:

4.扩展
最后,我们可以使用以下代码来复制Joy Division 专辑封面的可视化效果。
代码如下:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
if __name__ == "__main__":
url = "./data/pulsar.csv"
df = pd.read_csv(url, header=None)
df = df.stack().reset_index()
df.columns = ['idx', 'x', 'y']
sns.set_theme(rc={"axes.facecolor": (0, 0, 0, 0), 'figure.facecolor':'#000000', 'axes.grid':False})
g = sns.FacetGrid(df, row='idx', aspect=50, height=0.4)
# Draw the densities in a few steps
g.map(sns.lineplot, 'x', 'y', clip_on=False, alpha=1, linewidth=1.5)
g.map(plt.fill_between, 'x', 'y', color='#000000')
g.map(sns.lineplot, 'x', 'y', clip_on=False, color='#ffffff', lw=2)
# Set the subplots to overlap
g.fig.subplots_adjust(hspace=-0.95)
g.set_titles("")
g.set(yticks=[], xticks=[], ylabel="", xlabel="")
g.despine(bottom=True, left=True)
plt.savefig('joy.png', facecolor='#000000')运行结果如下:

5.结论
总体而言,山脊图非常适合关注数据的分布对比。其吸引人的美学设计能引起观众共鸣,是向用户展示数据分布对比分析的绝佳选择。
到此这篇关于python数据可视化Seaborn绘制山脊图的文章就介绍到这了,更多相关Seaborn绘制山脊图内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









