Matplotlib:散点图圆心

2 投票
1 回答
2143 浏览
提问于 2025-04-17 08:18

我有一个使用Matplotlib绘制的散点图,里面画了三个不同的圆。我想找到这三个圆的中心点在坐标轴上的x和y坐标,也就是在0到1之间的数字。我这么做是因为我想把这个图保存为.png文件,并且想在这个文件的(512, 1024)空间中找到对应的x和y点。

我试着用下面的代码,但我不知道怎么理解它打印出来的顶点和代码:

ax = fig.gca()
for collection in ax.collections:
    for path in collection._paths:
        for p in path.iter_segments():
            print p

它打印出了10个数组,分别对应这三个圆,但我觉得这没什么意义,因为只有三个圆,我找不到任何文档来解释这个情况:

(array([ 0. , -0.5]), 1)

(array([ 0.13260155, -0.5 , 0.25978994, -0.44731685, 0.35355339, -0.35355339]), 4)

(array([ 0.44731685, -0.25978994, 0.5 , -0.13260155, 0.5 , 0. ]), 4)

(array([ 0.5 , 0.13260155, 0.44731685, 0.25978994, 0.35355339, 0.35355339]), 4)

(array([ 0.25978994, 0.44731685, 0.13260155, 0.5 , 0. , 0.5 ]), 4)

(array([-0.13260155, 0.5 , -0.25978994, 0.44731685, -0.35355339, 0.35355339]), 4)

(array([-0.44731685, 0.25978994, -0.5 , 0.13260155, -0.5 , 0. ]), 4)

(array([-0.5 , -0.13260155, -0.44731685, -0.25978994, -0.35355339, -0.35355339]), 4)

(array([-0.25978994, -0.44731685, -0.13260155, -0.5 , 0. , -0.5 ]), 4)

(array([ 0. , -0.5]), 79)

谢谢

1 个回答

3

我觉得你可能会对 ax.transData 这个转换感兴趣。通过使用 transform 方法,你可以把数据单位的点转换成显示单位的点。想了解更多,可以看看这个 转换教程

下面我有一个例子,里面有一个填满整个图表的坐标轴,这样更容易理解这个转换。我在散点图上设置了三个点,然后我用这些数据,通过转换,找到了每个点对应的像素位置。

import matplotlib.pyplot as plt

x = [1,2,4]
y = [1,3,2]

fig1 = plt.figure(figsize=(5,5),dpi=100)
ax = fig1.add_axes([0,0,1,1])

ax.scatter(x,y)

ax.set_xlim(0,5)
ax.set_ylim(0,5)
transDataToFig1 = ax.transData+fig1.transFigure.inverted()
for ix,iy in zip(x,y):
    inDots = ax.transData.transform((ix,iy))
    inFigIndirect = fig1.transFigure.inverted().transform(inDots)
    inFigDirect = transDataToFig1.transform((ix,iy))
    print inDots,"->",inFigIndirect," or ",inFigDirect

fig1.savefig('scatterPos1.png')

因为 (1) 坐标轴覆盖了整个图形,(2) 坐标轴的范围设置为0到5,(3) 图形的大小设置为5x5英寸,分辨率为100像素每英寸,所以一个坐标单位对应100个像素。这一点在输出中得到了确认:

[ 100.  100.] -> [ 0.2  0.2]  or  [ 0.2  0.2]
[ 200.  300.] -> [ 0.4  0.6]  or  [ 0.4  0.6]
[ 400.  200.] -> [ 0.8  0.4]  or  [ 0.8  0.4]

上面的代码还展示了如何从dpi(每英寸的点数)转换到图形单位(在bbox内的值,范围在0到1之间),并提供了一个转换流程的例子(可以参考上面的教程)。作为参考,这就是生成的图形:

enter image description here

现在如果你再做一个包含子图的第二个图形,这个过程依然有效,但像素值就没那么特别了。举个例子,这段额外的代码:

fig2=plt.figure(figsize=(5,5),dpi=100)
ax1 = fig2.add_subplot(121)
ax2 = fig2.add_subplot(122)
ax1.scatter(x,y)
ax1.set_xlim(0,5)
ax2.set_ylim(0,5)
ax2.plot(range(10))

transDataToFig2 = ax1.transData+fig2.transFigure.inverted()
for ix,iy in zip(x,y):
    inDots = ax1.transData.transform((ix,iy))
    inFigIndirect = fig2.transFigure.inverted().transform(inDots)
    inFigDirect = transDataToFig2.transform((ix,iy))
    print inDots,"->",inFigIndirect," or ",inFigDirect

fig2.savefig('scatterPos2.png')

生成了这个图形:

enter image description here

以及这个输出:

[  97.72727273  116.66666667] -> [ 0.19545455  0.23333333]  or  [ 0.19545455  0.23333333]
[ 132.95454545  383.33333333] -> [ 0.26590909  0.76666667]  or  [ 0.26590909  0.76666667]
[ 203.40909091  250.        ] -> [ 0.40681818  0.5       ]  or  [ 0.40681818  0.5       ]

注意,在这种情况下,转换对你使用的坐标轴是敏感的。我使用了坐标轴 ax1,因为它是与存储在 xy 中的点对应的散点图。

这些例子和你想做的事情有些不同。你有像素中的 x,y 位置,想知道选中了哪个点。这实际上是 transData 的反向转换,通常(未反向)是把数据单位的点转换回显示单位的点(像素)。每个坐标轴都有自己独特的 transData,而且对坐标轴的范围很敏感。

举个例子,如果我模拟在位置 (120,480) 的鼠标点击(以像素为单位),那么每个子图都会把这个位置转换成不同的数据坐标,像这样:

click = (120,480)
print "Click ",click," transforms into:"
print ax1.transData.inverted().transform(click)," for axes 1"
print ax2.transData.inverted().transform(click)," for axes 2"

这会得到:

Click  (120, 480)  transforms into:
[ 1.63225806  3.725     ]  for axes 1
[-7.86193548  9.675     ]  for axes 2

注意,ax2(第二个子图)的转换导致了一个负的 x 位置。这是因为像素位置 (120,480) 超出了第二个子图的 x 范围。

撰写回答