如何确定中线的小提琴图边缘的 x 值
Posted
技术标签:
【中文标题】如何确定中线的小提琴图边缘的 x 值【英文标题】:How to determine the x value on the edge of the violinplot for a mean line 【发布时间】:2021-11-13 16:25:01 【问题描述】:我试图在小提琴图上画一条平均线,因为我无法找到一种方法让 sns 替换来自“四分位数”的“中位数”线,所以我决定编写代码,以便在每种情况下它绘制在顶部。我计划在我拥有的三个图表的平均值(y 值)上使用 plt.plot 绘制水平线。
我有确切的 y(高度)值,我希望在其中绘制水平线,但是,我很难找出每个小提琴图在该特定 y 值上的界限。我知道,因为它是对称的,所以域是(-x,x),所以我需要一种方法来找到“x”值,以便我能够添加 3 条水平线,每条水平线都以我拥有的小提琴图为界。
这是我的代码,plt.plot
的 x 值为 -0.37
,这是我通过反复试验找到的,我希望 python 为给定的 y 值找到它。强>
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
data = [2.57e-05, 4.17e-06, -5.4e-06, -5.05e-06, 1.15e-05, -6.7e-06, 1.01e-05, 5.53e-06, 8.13e-06, 1.27e-05, 1.11e-06, -2.87e-06, -1.38e-06, -1.07e-05, -8.04e-06, 4.77e-06, 3.22e-07, 9.86e-06, 1.38e-05, 1.32e-05, -3.48e-06, -4.69e-06, 8.15e-06, 4.21e-07, 2.71e-06, 7.52e-08, 1.04e-06, -1.92e-06, -4.08e-06, 4.76e-06]
vg = sns.violinplot(data=data, inner="quartile", scale="width")
a = sns.pointplot(data=data, zlinestyles='-', join=False, ci=None, color='red')
for p in vg.lines:
p.set_linestyle('-')
p.set_linewidth(0.8) # Sets the thickness of the quartile lines
p.set_color('white') # Sets the color of the quartile lines
p.set_alpha(0.8)
for p in vg.lines[1::3]: # these are the median lines; not means
p.set_linestyle('-')
p.set_linewidth(0) # Sets the thickness of the median lines
p.set_color('black') # Sets the color of the median lines
p.set_alpha(0.8)
# add a mean line from the edge of the violin plot
plt.plot([-0.37, 0], [np.mean(data), np.mean(data)], 'k-', lw=1)
plt.show()
请参阅我删除了中点但留下四分位线的图片,我想在可见蓝点的地方绘制平均线
这是我用我通过反复试验找到的 x 值绘制 plt.plot 后的图片:仅适用于我的情况
【问题讨论】:
希望答案是有帮助的。彻底回答问题很费时间。如果您的问题已解决,请接受解决方案。 ✔ 位于答案左上角的 ▲/▼ 箭头下方。如果出现更好的解决方案,则可以接受新的解决方案。如果您的声望超过 15,您还可以使用 ▲/▼ 箭头对答案的有用性进行投票。 如果解决方案无法回答问题,请发表评论。 What should I do when someone answers my question?。谢谢。 【参考方案1】:你可以画一条太长的线,然后用多边形剪成小提琴。
请注意,inner='quartile'
显示 25%、50% 和 75% 线。 50% 线也称为中位数。这类似于boxplots 通常的绘制方式。以过于相似的方式显示平均值是相当令人困惑的。这就是为什么 seaborn(和许多其他库)更喜欢将平均值显示为一个点。
这是一些示例代码(请注意,sns.violinplot
的返回值是 ax
,并且命名非常不同,因此很难找到进入 matplotlib 和 seaborn 文档和示例的方法)。
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
import seaborn as sns
import pandas as pd
import numpy as np
tips = sns.load_dataset('tips')
tips['day'] = pd.Categorical(tips['day'])
ax = sns.violinplot(data=tips, x='day', y='total_bill', hue='day', inner='quartile', scale='width', dodge=False)
sns.pointplot(data=tips, x='day', y='total_bill', join=False, ci=None, color='yellow', ax=ax)
ax.legend_.remove()
for p in ax.lines:
p.set_linestyle('-')
p.set_linewidth(0.8) # Sets the thickness of the quartile lines
p.set_color('white') # Sets the color of the quartile lines
p.set_alpha(0.8)
for x, (day, violin) in enumerate(zip(tips['day'].cat.categories, ax.collections)):
line = ax.hlines(tips[tips['day'] == day]['total_bill'].mean(), x - 0.5, x + 0.5, color='black', ls=':', lw=2)
patch = PathPatch(violin.get_paths()[0], transform=ax.transData)
line.set_clip_path(patch) # clip the line by the form of the violin
plt.show()
更新为使用数据列表列表:
data = [np.random.randn(10, 7).cumsum(axis=0).ravel() for _ in range(3)]
ax = sns.violinplot(data=data, inner='quartile', scale='width', palette='Set2')
# sns.pointplot(data=data, join=False, ci=None, color='red', ax=ax) # shows the means
ax.set_xticks(range(len(data)))
ax.set_xticklabels(['I' * (k + 1) for k in range(len(data))])
for p in ax.lines:
p.set_linestyle('-')
p.set_linewidth(0.8) # Sets the thickness of the quartile lines
p.set_color('white') # Sets the color of the quartile lines
p.set_alpha(0.8)
for x, (data_x, violin) in enumerate(zip(data, ax.collections)):
line = ax.hlines(np.mean(data_x), x - 0.5, x + 0.5, color='black', ls=':', lw=2)
patch = PathPatch(violin.get_paths()[0], transform=ax.transData)
line.set_clip_path(patch)
plt.show()
PS:关于enumerate(zip(...))
的一些进一步解释
for data_x in data:
将遍历列表data
的条目,首先将data[0]
分配给data_x
等。
for x, data_x in enumerate(data):
将遍历列表data
的条目,同时将变量x
从0
增加到1
,最后增加到2
。
for data_x, violin in zip(data, ax.collections):
将 data_x
循环遍历列表 data
的条目,同时通过存储在 ax.collections
的列表中的变量 violin
(这是 matplotlib 存储小提琴形状的地方)
for x, (data_x, violin) in enumerate(zip(data, ax.collections)): combines the enumeration with
zip`
【讨论】:
我很困惑如何在我的代码中实现这个方法:我正在使用数组,所以我不太明白 for 循环是什么:for x, (day, violin) in enumerate(zip (tips['day'].cat.categories, ax.collections)): 正在迭代。 x, (day,violin) 真正代表什么?而不是 enumerate(zip(..)) 真正在做什么?顺便谢谢你的帮助,我一直在到处寻找答案,再多一点帮助就太好了! 另外,当我调整一个类似的公式时,我的 python 不明白什么是“小提琴”,看着我尖叫。 @TrentonMcKinney 最初不是,然后我尝试了 Jupiter,它做到了 @TrentonMcKinney 非常感谢您提供的附加代码。我更新了它以在循环中省略[:4]
,并且更类似于OP。
如果这回答了您的问题,您可能会将marking 的答案视为已接受。以上是关于如何确定中线的小提琴图边缘的 x 值的主要内容,如果未能解决你的问题,请参考以下文章