Python中的分类气泡图

Posted

技术标签:

【中文标题】Python中的分类气泡图【英文标题】:Categorical bubble plot in Python 【发布时间】:2021-05-23 11:07:46 【问题描述】:

我有一个包含很多分类变量和二进制目标变量的数据集。 Python 或其他基于开源 GUI 的软件中提供了哪些软件包,我可以在其中散点图 X 和 Y 轴上的两个分类变量并将目标变量用作色调?

我查看了 Seaborn 的 catplot,但为此,一个轴必须是数字的,而另一个轴必须是分类的。所以它不适用于这种情况。

例如,您可以使用以下内容:

import seaborn as sns
data = sns.load_dataset('titanic')

这是我想要的剧情功能

X 轴 - 'embark_town' Y 轴 - '类' 色调 - '活着'

【问题讨论】:

你可以用 pyplot 来做。提供数据样本和预期输出。 pakpe - 我已将数据添加到帖子中。请回复。 @Mr. T - Seaborn 很漂亮,但非 Seaborn 也可以。 Alive 具有值“是”和“否”。我在脑海中将 X 和 Y 变量的频率显示为是和否的气泡。不确定这在任何 python 包中是否可行。我尝试在谷歌上搜索,但找不到任何内容。 【参考方案1】:

我的观点是,如果您必须大量重新排列 seaborn 图,您也可以使用 matplotlib 从头开始​​创建此图。这使我们有机会采用不同的方法来显示此分类与分类图:

import matplotlib.pyplot as plt
from matplotlib.markers import MarkerStyle
import numpy as np

#dataframe and categories 
import seaborn as sns
df = sns.load_dataset('titanic')

X = "embark_town"
Y = "class"
H = "alive"
bin_dic = 0: "yes", 1: "no"

#counting the X-Y-H category entries
plt_df = df.groupby([X, Y, H]).size().to_frame(name="vals").reset_index()

#figure preparation with grid and scaling
fig, ax = plt.subplots(figsize=(9, 6))
ax.set_ylim(plt_df[Y].unique().size-0.5, -0.5)
ax.set_xlim(-0.5, plt_df[X].unique().size+1.0)
ax.grid(ls="--")

#upscale factor for scatter marker size
scale=10000/plt_df.vals.max()
#left marker for category 0
ax.scatter(plt_df[plt_df[H]==bin_dic[0]][X], 
           plt_df[plt_df[H]==bin_dic[0]][Y], 
           s=plt_df[plt_df[H]==bin_dic[0]].vals*scale, 
           c=[(0, 0, 1, 0.5)], edgecolor="black", marker=MarkerStyle("o", fillstyle="left"), 
           label=bin_dic[0])
#right marker for category 1
ax.scatter(plt_df[plt_df[H]==bin_dic[1]][X], 
           plt_df[plt_df[H]==bin_dic[1]][Y], 
           s=plt_df[plt_df[H]==bin_dic[1]].vals*scale, 
           c=[(1, 0, 0, 0.5)], edgecolor="black", marker=MarkerStyle("o", fillstyle="right"), 
           label=bin_dic[1])

#legend entries for the two categories
l = ax.legend(title="Survived the catastrophe", ncol=2, framealpha=0, loc="upper right", columnspacing=0.1,labelspacing=1.5) 
l.legendHandles[0]._sizes = l.legendHandles[1]._sizes = [800]

#legend entries representing sizes
bubbles_n=5
bubbles_min = 50*(1+plt_df.vals.min()//50)
bubbles_step = 10*((plt_df.vals.max()-bubbles_min)//(10*(bubbles_n-1)))
bubbles_x = plt_df[X].unique().size+0.5

for i, bubbles_y in enumerate(np.linspace(0.5, plt_df[Y].unique().size-1, bubbles_n)): 
    #plot each legend bubble to indicate different marker sizes
    ax.scatter(bubbles_x, 
               bubbles_y,
               s=(bubbles_min + i*bubbles_step) * scale,
               c=[(1, 0, 1, 0.6)], edgecolor="black")
    #and label it with a value
    ax.annotate(bubbles_min+i*bubbles_step, xy=(bubbles_x, bubbles_y), 
                ha="center", va="center",
                fontsize="large", fontweight="bold", color="white")

plt.show()

【讨论】:

非常感谢!【参考方案2】:

Seaborn 像 matplotlib 一样支持分类变量与分类变量的绘图。可以创建允许查看两个类别的半透明标记,尽管如果两者具有相似的大小,这可能难以与一个标记区分开来。基本图相当简单 - 我们使用 groupby 和 size 转换数据框,以计算每个三胞胎出发城镇 - 班级 - 活着类别的条目,然后创建一个以计数值作为标记大小的散点图。但是,图例条目是这里复杂的部分。标记大小在情节中很小或在图例中很大。我试图平衡这一点,但我对结果不满意。这里需要大量的手动调整,所以 seaborn 在这里没有真正的优势。欢迎任何有关如何在 seaborn 中简化此操作的建议。

import seaborn as sns
import matplotlib.pyplot as plt

#dataframe and categories 
df = sns.load_dataset('titanic')
X = "embark_town"
Y = "class"
H = "alive"

#counting the X-Y-H category entries
plt_df = df.groupby([X, Y, H]).size().to_frame(name="people").reset_index()

#figure preparation with grid and scaling
fig, ax = plt.subplots(figsize=(6,4))
ax.set_ylim(plt_df[Y].unique().size-0.5, -0.5)
ax.set_xlim(-0.5, plt_df[X].unique().size+1.0)
ax.grid(ls="--")

#the actual scatterplot with markersize representing the counted values
sns.scatterplot(x=X,
                y=Y,
                size="people",
                sizes=(100, 10000),
                alpha=0.5,
                edgecolor="black",
                hue=H,
                data=plt_df,
                ax=ax)

#creating two legends because the hue markers differ in size from the others
handles, labels = ax.get_legend_handles_labels()
l = ax.legend(handles[:3], labels[:3], title="The poor die first", markerscale=2, loc="upper right")
ax.add_artist(l)
#and seaborn plots the size markers in black, so you would get massive black blobs in the legend
#we change the color and make them transparent
for handle in handles:
    handle.set_facecolors((0, 1, 1, 0.5))
ax.legend(handles[4::2], labels[4::2], title="N° of people", loc="lower right", handletextpad=4, labelspacing=3, markerfirst=False)
plt.tight_layout()
plt.show()

样本输出:

【讨论】:

真的,非常感谢。非常感谢。

以上是关于Python中的分类气泡图的主要内容,如果未能解决你的问题,请参考以下文章

新冠疫情形势气泡图(python还有这么可爱的气泡图哦)

用 Python 在一个矩形中打包气泡图堆栈

如何在 python/matplotlib 中制作居中气泡图

如何根据交叉点的大小在 Plotly 中构建具有气泡大小的气泡图?

背景图像未与 s-s-rS 中的气泡图对齐

GO/KEGG功能富集分析及气泡图