Matplotlib:散点图圆心
我有一个使用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 个回答
我觉得你可能会对 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之间),并提供了一个转换流程的例子(可以参考上面的教程)。作为参考,这就是生成的图形:
现在如果你再做一个包含子图的第二个图形,这个过程依然有效,但像素值就没那么特别了。举个例子,这段额外的代码:
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')
生成了这个图形:
以及这个输出:
[ 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
,因为它是与存储在 x
和 y
中的点对应的散点图。
这些例子和你想做的事情有些不同。你有像素中的 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 范围。