绘制连接两个群图的各个数据点的彩色线

问题描述 投票:0回答:2

我有:

import numpy as np
import pandas as pd
import seaborn as sb
import matplotlib.pyplot as plt

# Generate random data
set1 = np.random.randint(0, 40, 24)
set2 = np.random.randint(0, 100, 24)

# Put into dataframe and plot
df = pd.DataFrame({'set1': set1, 'set2': set2})
data = pd.melt(df)
sb.swarmplot(data=data, x='variable', y='value')

用seaborn的swarmplot函数绘制的两个随机分布: The two random distributions plotted with seaborns swarmplot function

我希望两个分布的各个图都用彩色线连接,以便数据框中第 1 组的第一个数据点与第 2 组的第一个数据点连接。 我意识到如果没有seaborn,这可能会相对简单,但我想保留各个数据点不重叠的功能。 有没有办法访问seaborn swarmfunction中的各个绘图坐标?

python matplotlib seaborn swarmplot
2个回答
5
投票

编辑:感谢@Mead,他在 2021 年 8 月 23 日之前指出了我的帖子中的一个错误(我忘记对先前版本中的位置进行排序)。

我尝试了Paul Brodersen给出了很好的答案,尽管他这么说

疯狂就在于此

...我实际上认为这非常简单并且产生了很好的结果:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# Generate random data
rng = np.random.default_rng(42)
set1 = rng.integers(0, 40, 5)
set2 = rng.integers(0, 100, 5)

# Put into dataframe
df = pd.DataFrame({"set1": set1, "set2": set2})
print(df)
data = pd.melt(df)

# Plot
fig, ax = plt.subplots()
sns.swarmplot(data=data, x="variable", y="value", ax=ax)

# Now connect the dots
# Find idx0 and idx1 by inspecting the elements return from ax.get_children()
# ... or find a way to automate it
idx0 = 0
idx1 = 1
locs1 = ax.get_children()[idx0].get_offsets()
locs2 = ax.get_children()[idx1].get_offsets()

# before plotting, we need to sort so that the data points
# correspond to each other as they did in "set1" and "set2"
sort_idxs1 = np.argsort(set1)
sort_idxs2 = np.argsort(set2)

# revert "ascending sort" through sort_idxs2.argsort(),
# and then sort into order corresponding with set1
locs2_sorted = locs2[sort_idxs2.argsort()][sort_idxs1]

for i in range(locs1.shape[0]):
    x = [locs1[i, 0], locs2_sorted[i, 0]]
    y = [locs1[i, 1], locs2_sorted[i, 1]]
    ax.plot(x, y, color="black", alpha=0.1)

打印:

   set1  set2
0     3    85
1    30     8
2    26    69
3    17    20
4    17     9

您可以看到数据在图中进行了相应链接。

enter image description here

更新

如果您不想手动或通过其他方式查找

ax.get_children()
的索引,您也可以使用下面的函数,例如本示例中的
locs1, locs2 = find_locs(ax, 2, 5)

def find_locs(ax, ncols, ndots):
    """Find objects in axes corresponding to plotted dots.

    Parameters
    ----------
    ax : plt.Axes
        The axes of the plot.
    ncols : int
        The number of stripplot columns in the plot.
    ndots : int
        The number of dots per column in the plot.

    Returns
    -------
    locs : list of np.ndarray
        `locs` is of length `ncols`, with each np.ndarray in `locs` corresponding
        to a column in the plot. The np.ndarray  is of shape (`ndots`, 2),
        corresponding to the (x,y) offset of each dot in that column.
    """
    # see also https://stackoverflow.com/a/63171175/5201771
    locs = []
    for child in ax.get_children():
        try:
            offsets = child.get_offsets()
        except AttributeError:
            continue

        _r, _c = offsets.shape  # _c is 2 for "x" and "y"
        if _c == 2 and _r == ndots:
            locs.append(offsets)

    if len(locs) == ncols:
        return locs
    else:
        raise RuntimeError("Encountered problems identifying dots in plot.")

1
投票

当然,这是可能的(但你真的不想这样做)。

seaborn.swarmplot
返回轴实例(此处:
ax
)。您可以抓住孩子
ax.get_children
来获取所有情节元素。您将看到每组点都有一个
PathCollection
类型的元素。您可以使用
PathCollection.get_offsets()
方法确定 x、y 坐标。

我不建议你这样做!疯狂就是这样。

我建议您查看源代码(在此处找到),并从

_PairedSwarmPlotter
派生您自己的
_SwarmPlotter
并根据您的需要更改
draw_swarmplot
方法。

© www.soinside.com 2019 - 2024. All rights reserved.