【问题标题】:Seaborn jointplot link x-axis to Matplotlib subplotsSeaborn jointplot 将 x 轴链接到 Matplotlib 子图
【发布时间】:2021-09-30 22:54:52
【问题描述】:

有没有办法将使用 vanilla Matplotlib 创建的附加子图添加到(下方)Seaborn 联合图,共享 x 轴?理想情况下,我想控制联合图和附加图之间的比率(类似于gridspec_kw={'height_ratios':[3, 1, 1]}

我试图通过在 Matplotlib 子图中调整 figsize 来伪造它,但是当边缘图中的 KDE 曲线发生变化时,它显然不能很好地工作。虽然我可以手动调整输出 PNG 的大小以缩小/放大其中一个数字,但我希望所有内容都自动对齐。

我知道联合网格的设置方式很棘手,但对于熟悉 Seaborn 基础的人来说,这可能相当简单。

这是一个最小的工作示例,但有两个单独的数字:

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

图一

diamonds = sns.load_dataset('diamonds')
g = sns.jointplot(
    data=diamonds,
    x="carat",
    y="price",
    hue="cut",
    xlim=(1, 2),
)
g.ax_marg_x.remove()

图2

fig, (ax1, ax2) = plt.subplots(2,1,sharex=True)
ax1.scatter(x=diamonds["carat"], y=diamonds["depth"], color="gray", edgecolor="black")
ax1.set_xlim([1, 2])
ax1.set_ylabel("depth")
ax2.scatter(x=diamonds["carat"], y=diamonds["table"], color="gray", edgecolor="black")
ax2.set_xlabel("carat")
ax2.set_ylabel("table")

期望的输出:

【问题讨论】:

标签: matplotlib seaborn jointplot


【解决方案1】:

我认为在这种情况下,使用 matplotlib 函数设置图形比从与用例不匹配的 seaborn 图形布局向后工作要好。

如果您有一个非完整的子图网格,您必须决定是否要 (A) 设置所有子图,然后删除您不想要的子图,或者 (B) 显式添加每个子图你想要的子图。让我们在这里选择选项 A。

figsize = (6, 8)
gridspec_kw = dict(
    nrows=3, ncols=2,
    width_ratios=[5, 1],
    height_ratios=[4, 1, 1],
)
subplot_kw = dict(sharex="col", sharey="row")
fig = plt.figure(figsize=figsize, constrained_layout=True)
axs = fig.add_gridspec(**gridspec_kw).subplots(**subplot_kw)

sns.kdeplot(data=df, y="price", hue="cut", legend=False, ax=axs[0, 1])
sns.scatterplot(data=df, x="carat", y="price", hue="cut", ax=axs[0, 0])
sns.scatterplot(data=df, x="carat", y="depth", color=".2", ax=axs[1, 0])
sns.scatterplot(data=df, x="carat", y="table", color=".2", ax=axs[2, 0])

axs[0, 0].set(xlim=(1, 2))

axs[1, 1].remove()
axs[2, 1].remove()

顺便说一句,这几乎使用plt.subplot_mosaic 会更容易一些,但它还不支持轴共享。

【讨论】:

  • 您是否还需要hue_order 左右来确保散点图和kdeplot 使用相同颜色的色调以获得相同的值?
  • 不,它们都在消耗完整的色调向量,因此它们将具有相同的默认映射。当不同方面获取数据集的子集时,您会遇到麻烦,这些子集的值可能以不同的顺序出现。
【解决方案2】:

您可以使用jointplot() 创建的图形,移动其填充(使用subplots_adjust())并添加2 个额外的轴。

示例代码需要针对每种特定情况进行一些调整。

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import seaborn as sns

diamonds = sns.load_dataset('diamonds')
g = sns.jointplot(data=diamonds, x="carat", y="price", hue="cut",
                  xlim=(1, 2), height=12)
g.ax_marg_x.remove()
g.fig.subplots_adjust(left=0.08, right=0.97, top=1.05, bottom=0.45)

axins1 = inset_axes(g.ax_joint, width="100%", height="30%",
                    bbox_to_anchor=(0, -0.4, 1, 1),
                    bbox_transform=g.ax_joint.transAxes, loc=3, borderpad=0)
axins2 = inset_axes(g.ax_joint, width="100%", height="30%",
                    bbox_to_anchor=(0, -0.75, 1, 1),
                    bbox_transform=g.ax_joint.transAxes, loc=3, borderpad=0)
shared_x_group = g.ax_joint.get_shared_x_axes()
shared_x_group.remove(g.ax_marg_x)
shared_x_group.join(g.ax_joint, axins1)
shared_x_group.join(g.ax_joint, axins2)

axins1.scatter(x=diamonds["carat"], y=diamonds["depth"], color="grey", edgecolor="black")
axins1.set_ylabel("depth")
axins2.scatter(x=diamonds["carat"], y=diamonds["table"], color="grey", edgecolor="black")
axins2.set_xlabel("carat")
axins2.set_ylabel("table")
g.ax_joint.set_xlim(1, 2)
plt.setp(axins1.get_xticklabels(), visible=False)
plt.show()

PS:How to share x axes of two subplots after they have been created 包含一些关于共享轴的信息(尽管在这里您只需为每个子图设置 xlim 即可获得相同的效果)。

定位新轴的代码改编自tutorial example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-28
    • 2019-12-07
    • 2021-03-10
    • 2019-02-03
    • 2020-03-20
    • 1970-01-01
    • 2017-08-12
    • 2020-07-17
    相关资源
    最近更新 更多