Matplotlib - Python- GetDist 工具 - 通过调用两次绘图函数重叠 2 个三角形图(三联图):两者之间的可见优先级问题

Matplotlib - Python- GetDist tool - Overlapping 2 triangle plots (triplots) by calling twice the plot function: issue of visible priority between both

在 python3 中,我在使用工具 GetDist tool to produce triplot of covariance matrix.

时遇到了 2 个问题

1) 目前,我只需调用一次绘图函数 (triangle_plot) 就可以在同一张图上绘制 2 个协方差矩阵。将要绘制的协方差矩阵列表指定为第一个输入足以让每个矩阵具有 (1 sigma,2 sigma) 等高线。这里是一个由 2 个协方差矩阵生成的三重图示例(填充区域对应于 1 sigma 置信水平 (68%),阴影对应于 2 sigma C.L (95%))。颜色标识每个矩阵(此处为红色和蓝色):

我的主要目标是我想像这样按降序优先重叠:

1) 1 sigma blue disk of smallest ellipse (blue)
2) 1 sigma red disk of largest ellipse (red)
3) 2 sigma blue disk of smallest ellipse (shaded blue)
4) 2 sigma red disk of smallest ellipse (shaded red)

而在默认行为中,我有以下降序优先级:

1) 1 sigma blue disk of smallest ellipse (blue)
2) 2 sigma blue disk of smallest ellipse (shaded blue)
2) 1 sigma red disk of largest ellipse (red)
4) 2 sigma red disk of smallest ellipse (shaded red)

这里是生成上图的脚本:

g.triangle_plot([matrix1, matrix2],
                names,
                filled = True,                
                legend_labels = ['1240', '1560'],
                legend_loc = 'upper right',
                contour_colors = ['red','darkblue'],
                line_args = [{'lw':2, 'color':'red'},
                {'lw':2, 'color':'darkblue'}],
                )

最后,我只希望 1 西格玛红色圆盘不要被 2 西格玛蓝色阴影隐藏。

这是我想要的示例(注意,与上面的三联图相比,红色和蓝色之间存在反转):

不要在意黄色轮廓。如您所见,1 sigma 蓝色磁盘优先于 2 红色阴影 sigma 磁盘。这与我想要的行为完全相同。

在上面的三图中,我尝试了很多 alpha 参数,但由于颜色混合且不再与图例(红色和蓝色)对应,因此一团糟。

2) 鉴于我没有在 GetDist 的源代码中找到更改此优先级的事实,我尝试调用两次函数 triangle_plot 每次调用一个矩阵。

但不幸的是,2次调用后2个图没有重叠。只出现一个彩色三联图(最后一次调用的那个)。例如,如果我像这样连续调用 2 个(matrix 2 代表最大的红色椭圆,matrix1 代表最小的椭圆):

g.triangle_plot([matrix2],
                names,
                filled = True,                
                legend_labels = ['1560'],
                legend_loc = 'upper right',
                contour_colors = ['darkblue'],
                contours = 0,
                num_plot_contours = 0,
                line_args = [{'lw':2, 'color':'darkblue'}]
                )

g.triangle_plot([matrix1],
                names,
                filled = True,                
                legend_labels = ['1240'],
                legend_loc = 'upper right',            
                contour_colors = ['red'],
                contours = 1,
                num_plot_contours = 1,
                line_args = [{'lw':2, 'color':'red'}]
                )

是否可以保留第一个三联图(矩阵 2 以红色表示)并再次调用 triangle_plot 函数以重叠第一个三联图和第二个三联图(蓝色)?

事实上,这将允许我使用置信度标识符(C.L:68% 或 95%),然后解决这个优先级问题。

不幸的是,当我调用 2 次 triangle_plot 函数时,重叠不起作用:只保留最后一次调用,第一次调用似乎已从图中删除。

在这种三联图中强制重叠的方法是什么(重叠等高线但不重叠标签和刻度)?我们可以先验地认为这很简单,因为三联图只是 boxes/subplots) 但我不能仅仅设法执行这种重叠。我试图在两个调用之间插入:

plt.show(block=False)  # do not block

但这不起作用。我认为这是因为我在最后将图形保存在文件中:

# Save figure
g.fig.savefig('Comparison_Overlap.pdf')

更新 1

感谢 Stef。最后一个问题:水平和垂直 xticks 被轮廓和填充区域隐藏,我不知道后者是 zorder 哪个。这里有 2 个例子说明了这个问题:

可以看到0.95对应的xtick被mask了

可以看到右下角的xtick也被屏蔽了

更新 2

@Stef 的解决方案完美运行,但仍然存在一个小问题:xticks 和 yticks 被轮廓隐藏了。

默认情况下,xticks 的 z-orderof 由 :

给出
g.fig.axes[0].xaxis.get_major_ticks()[0].zorder

那个 returns : 0

所以,当我绘制等高线时,我在 triangle_plot 之后加上:

for ax in g.fig.axes:
  geo = ax.get_geometry()
  if (geo[2]-1) // geo[0] > (geo[2]-1) % geo[0]:
    for c,z in zip(ax.collections, [-1.7, -1.5, -0.1, -1.6, -1.4, -0.1]):
      c.zorder = z

这样,我可以让轮廓不被轮廓隐藏。例如,如下所示:

这个解决方案不是很容易,因为我必须处理负值 ([-1.7, -1.5, -0.1, -1.6, -1.4, -0.1])。

现在,感谢 @Stef,我可以修改 g.fig.axes[0].xaxis.get_major_ticks()[0].zorder 的值,例如等于 3,方法是:

# Modify z-order 
for mt in g.fig.axes[0].xaxis.get_major_ticks():
  mt.zorder = 3
for mt in g.fig.axes[0].yaxis.get_major_ticks():
  mt.zorder = 3

但如果我在那之后做:

for ax in g.fig.axes:
  geo = ax.get_geometry()
  if (geo[2]-1) // geo[0] > (geo[2]-1) % geo[0]:
    for c,z in zip(ax.collections, [1.6, 1.8, 2, 1.7, 1.9, 2]):
      c.zorder = z

xticks 仍然被轮廓隐藏,而阈值设置为 3:我不明白这种行为:

可能出了什么问题?

更新 3

这是我试图解决关于我想要的刻度优先级问题的最后一件事,即让 xticks/yticks 出现在轮廓前面,而不是即时出现的相反部分。

如果我默认打印 get_major_ticks()get_ticklines()[0]) 的值 zorder,我得到:

print('zorder1 = ', g.fig.axes[0].xaxis.get_major_ticks()[0].zorder)
print('zorder2 = ', g.fig.axes[0].xaxis.get_ticklines()[0].zorder)

==>

zorder1 =  0
zorder2 =  2.01

get_major_ticks()get_ticklines() 有什么区别?

你可以理解为什么我可以设法在所有轮廓前面设置刻度,即通过在 @Stef 给出的解决方案中设置负值:

for ax in g.fig.axes:
  geo = ax.get_geometry()
  if (geo[2]-1) // geo[0] > (geo[2]-1) % geo[0]:
    for c,z in zip(ax.collections, [-1.7, -1.5, -0.1, -1.6, -1.4, -0.1]):
      c.zorder = z

我可以修改上面的 zorder2 :

g.fig.axes[0].tick_params(zorder=3)

但我无法修改 zorder1(默认等于 0)。

如何更改 zorder10 值(引用 get_ticklines())?

这有点老套,但您可以稍后更改轮廓的 zorder。为此,我们采用下三角图并设置路径和线集合的 zorder 属性。它们按以下顺序出现:

  1. 第一个样本的 2 sigma 的填充区域
  2. 第一个样本的 1 个 sigma 的填充区域
  3. 第一个样本的轮廓线
  4. 第二个样本的 2 sigma 的填充区域
  5. 第二个样本的 1 sigma 的填充区域
  6. 第二个样本的轮廓线

原来所有的填充区域都有zorder1和所有的线2。我们根据需要设置它们,例如17, 19, 21, 18, 20, 21.

示例:

from getdist import plots, gaussian_mixtures
samples1, samples2 = gaussian_mixtures.randomTestMCSamples(ndim=4, nMCSamples=2)
g = plots.get_subplot_plotter()
g.triangle_plot([samples1, samples2], filled=True, legend_labels = ['Contour 1', 'Contour 2'])

for ax in g.fig.axes:
    geo = ax.get_geometry()
    if (geo[2]-1) // geo[0] > (geo[2]-1) % geo[0]:
       for c,z in zip(ax.collections, [17,19,21,18,20,21]):
           c.zorder = z