Python画图:matplotlib中的5套坐标系统
相信一定会有人对matplotlib中的各种坐标系统傻傻分不清楚吧,至少这个问题困扰了我很久,直到我开发PyComplexHeatmap包时才将这个问题彻底弄清楚。
比如ax.figure.transFigure
的坐标,用户空间数据坐标系统ax.transData
,和Axes
坐标系统ax.transAxes
等。
今天,我将把自己对这个问题的理解和积累的经验分享给大家,本教程将向大家展示matplotlib中的五大坐标系统,让大家一次性弄明python画图中的各种坐标。
import os,sys import matplotlib.pylab as plt %matplotlib inline
1. 显示坐标系统(display space)
单位:像素 (px)
plt.figure(figsize=(5,6),facecolor='skyblue') # ax=plt.gca() ax.set_facecolor('orange') plt.tight_layout() plt.show() print()
上面的代码,画了一个宽和高分别为5和6英寸(inches)的空图,那么上图中蓝色和橘黄色这两个部分,哪一个的宽和高才是5和6呢? 我们可以用ax.figure.get_window_extent来将整个图的宽、高和边界点的左边打印出来:
# figure box=ax.figure.get_window_extent() print("宽和高(单位:像素 px):",box.width,box.height) print("起点坐标(x0,y0):",box.x0,box.y0) # equal to: box.p0 print("右上角坐标(x1,y1):",box.x1,box.y1) # equal to: box.p1
宽和高(单位:像素 px): 500.0 600.0
起点坐标(x0,y0): 0.0 0.0
右上角坐标(x1,y1): 500.0 600.0
# Axes box=ax.get_window_extent() print("宽和高(单位:像素 px):",box.width,box.height) print("起点坐标(x0,y0):",box.x0,box.y0) # equal to: box.p0 print("右上角坐标(x1,y1):",box.x1,box.y1) # equal to: box.p1
宽和高(单位:像素 px): 427.09027777777777 540.7777777777776
起点坐标(x0,y0): 46.84722222222222 38.722222222222236
右上角坐标(x1,y1): 473.9375 579.4999999999999
print(ax.figure.get_size_inches()) #figure的大小,单位是英寸 print(ax.figure.dpi) #默认的像素为100,可以在plt.figure(dpi=300)中修改 print(ax.figure.dpi_scale_trans.transform((5,6))) #将5,6英寸转化为像素px
[5. 6.]
100.0
[500. 600.]
由此可见ax.figure.get_window_extent()才是我们设置的5,6英寸,也就是说上图中蓝色框框的宽和高才是5,6英寸,由于默认的dpi是100,所以是500和600像素(px)
请注意:像素=英寸*分辨率(dpi)
plt.figure(figsize=(5,6),facecolor='skyblue') # ax=plt.gca() ax.set_facecolor('orange') ax.scatter([0,1],[0,1],color='red') #默认transform=ax.transData, ax.scatter([0,1],[0,1],transform=ax.transAxes,color='purple',s=60,clip_on=False) ax.plot([0,1],[0,1],transform=ax.figure.transFigure,lw=5,color='yellow',zorder=100,clip_on=False) plt.show()
在上图中,画的三对点(或者线条),坐标全都是[0,0]和[1,1],但全都画在了不同的位置,这是为什么呢?
从中我们不难发现:
-
红色的点,用的坐标系统是【用户空间数据坐标系统】,也就是横轴和纵轴对应的(0,0)和(1,1)坐标;
-
紫色的点,用的是【轴(Axes)坐标系统】,也就是橘黄色框框中的坐标系统;
-
黄色的线条,用的是【图(figure)坐标系统】,也就是蓝色框框的坐标系统。
print("红色点在显示坐标系统中的坐标(px):\n",ax.transData.transform(((0,0),(1,1)))) print("紫色点在显示坐标系统中的坐标(px):\n",ax.transAxes.transform(((0,0),(1,1)))) print("黄色线条在显示坐标系统中的坐标(px):\n",ax.figure.transFigure.transform(((0,0),(1,1))))
红色点在显示坐标系统中的坐标(px):
[[ 80.11363636 87. ]
[432.38636364 507. ]]
紫色点在显示坐标系统中的坐标(px):
[[ 62.5 66. ]
[450. 528. ]]
黄色线条在显示坐标系统中的坐标(px):
[[ 0. 0.]
[500. 600.]]
所以,不管是用【户空间数据坐标系统】,轴(Axes)坐标系统】,【图(figure)坐标系统】还是【混合坐标系统】,要想展示在图中,最后都被matplotlib自动转换成了【显示坐标系统(display space)】,这样,才可以被我们看见。因此,可以说【显示坐标系统(display space)】是其它坐标系统的基础。
此外,与图1相比,图2中,黄色框与蓝色框之间的空隙变大了,我也没有完全弄明白这其中的原因,或许是自动聚焦,留一部分空隙。欢迎后台一起交流探讨。
【显示坐标系统】不适合用于直接画图,因为当你用鼠标对画出来的图进行缩放时,坐标就全都变了。下面,我们继续来介绍其它4中坐标系统:
2. figure 坐标系统
单位:百分比(fraction,介于0-1)
图2中,蓝色框的左下角,在【figure 坐标系统】中的坐标为[0,0],右上角的坐标为[1,1]
可以用ax.figure.transFigure.transform
将【figure 坐标系统】中的坐标转换为【显示坐标系统(display space)】中的像素:
print(ax.figure.transFigure.transform((0,0))) print(ax.figure.transFigure.transform((1,1)))
[0. 0.]
[500. 600.]
import matplotlib.pyplot as plt fig, ax = plt.subplots(facecolor='skyblue') ax.set_facecolor('orange') ax.plot([2.], [3.], 'ro') plt.text( # position text relative to data 2., 3., 'important point', # x, y, text, ha='center', va='bottom', # text alignment, transform=ax.transData # 可以不加,默认就是ax.transData ) plt.text( # position text relative to Axes 1.0, 1.0, 'axes corner', ha='right', va='top', transform=ax.transAxes ) plt.text( # position text relative to Figure 0.0, 1.0, 'figure corner', ha='left', va='top', transform=fig.transFigure ) plt.text( # position text absolutely at specific pixel on image 200, 300, 'pixel (200, 300)', ha='center', va='center', transform=None # 如果为None,那就是【显示坐标系统】 ) plt.show()
3. 用户空间数据坐标系统
单位:由用户提供的数据决定,整数或者小数
图2中,橘黄色框框内,横轴从0到1,纵轴也是从0到1
【用户空间数据坐标系统】是我们画图时最常用的坐标系统
可以用ax.transData.transform将【用户空间数据坐标系统】中的坐标转换为【显示坐标系统(display space)】中的像素:
ax.transData.transform([(0,0),(1,1)]) #将用户数据坐标系统转换为display系统
array([[ 80.11363636, 87. ],
[432.38636364, 507. ]])
【用户空间数据坐标系统】,由 xlim 和 ylim 控制。向坐标轴添加数据,Matplotlib 都会自动更新数据界限。
import matplotlib.pyplot as plt import numpy as np import matplotlib.patches as mpatches x = np.arange(0, 10, 0.005) y = np.exp(-x/2.) * np.sin(2*np.pi*x) fig, ax = plt.subplots() ax.plot(x, y) ax.set_xlim(0, 10) ax.set_ylim(-1, 1) plt.show()
4. 轴(Axes)坐标系统
单位:百分比,介于0-1之间
图2中,橘黄色框框内,最左下角坐标为[0,0],[0.5,0.5]是中心,右上角坐标为[1,1]
(-0.1,1.1)位于坐标轴的左侧和上方,当将文本放置在axes中时,这个坐标系非常有用,因为我们通常希望在固定的位置 (例如axes窗格的左上角) 中写一个文本,并且在平移或缩放时该位置保持不变。
可以用ax.transAxes.transform
将【用户空间数据坐标系统】中的坐标转换为【显示坐标系统(display space)】中的像素:
用ax.get_window_extent().get_points()
可以获取轴的左下角和右上角坐标以及宽度和高度(单位是显示坐标系统中的像素)
ax.xaxis.set_label_coords
#参数也是轴(Axes)坐标系统中的坐标
import random fig = plt.figure() for i, label in enumerate(('A', 'B', 'C', 'D')): ax = fig.add_subplot(2, 2, i+1) ax.text(0.05, 0.95, label, transform=ax.transAxes, fontsize=16, fontweight='bold', va='top',color='red') ax.set_xlim([random.randint(0,50),random.randint(50,100)]) ax.set_ylim([0,random.randint(10,100)]) ax.set_facecolor('yellowgreen') plt.show()
入上图所示,当我们想要在轴的左上角画一个图例、文本标签等的时候,就可以用到轴坐标系统,不管xlim
和ylim
怎么变化,我们的文本位置都是固定的。
5. 混合坐标系统
在一个 axis 上使用 data 坐标,在另一个上使用 axes 坐标系。在混合 axes 和 data 坐标系的 blended 混合坐标系统中绘图非常有用,例如,创建一个水平跨距突出显示 y 数据的某些区域,但在 x-axis 轴上的跨距不受 x 数据的限制,移动和缩放等的影响
print("figure:") print(ax.figure.get_window_extent().get_points()) print("axes:") print(ax.get_window_extent().get_points()) print("xlim",ax.get_xlim()) print("ylim",ax.get_ylim()) print("get_xaxis_transform (4,1):") print(ax.get_xaxis_transform().transform_point((4,1))) #input x should be data coordinates, input y should between [0,1] print("get_yaxis_transform (1,4):") print(ax.get_yaxis_transform().transform_point((1,4))) #x should between [0,1], y is data coordinate ax.xaxis.label.get_position() ax.get_yaxis_transform().transform_point(ax.xaxis.label.get_position()) #convert into display coordinates.
figure:
[[ 0. 0.]
[640. 480.]]
axes:
[[350.54545455 52.8 ]
[576. 220.8 ]]
xlim (48.0, 81.0)
ylim (0.0, 100.0)
get_xaxis_transform (4,1):
[ 49.93939394 220.8 ]
get_yaxis_transform (1,4):
[576. 59.52]
array([463.27272727, 60.26666667])
import random fig = plt.figure() for i, label in enumerate(('A', 'B', 'C', 'D')): ax = fig.add_subplot(2, 2, i+1) ax.text(50, 0.95, label, transform=ax.get_xaxis_transform(), fontsize=16, fontweight='bold', va='top',color='red') ax.set_xlim([random.randint(0,50),random.randint(50,100)]) ax.set_ylim([0,random.randint(10,100)]) ax.set_facecolor('yellowgreen') plt.show()
同样的例子,我们把文本的x坐标改成50,y还是0.95不变,transform改成了混合坐标系get_xaxis_transform
,意思是,x用用户空间数据坐标系统,y用轴坐标系统。
不管xlim
和ylim
怎么变,我们添加的文本的横坐标都是50,纵坐标都位于y轴的顶部。
混合坐标系统,还可以用matplotlib.transforms.blended_transform_factory
函数自由组合和搭配,比如:
import matplotlib trans = matplotlib.transforms.blended_transform_factory( ax.figure.transFigure, ax.transAxes) # x轴用【figure坐标系统】,而y轴用【轴坐标系统】
print(trans.transform((1,1))) print("figure:") print(ax.figure.get_window_extent().get_points()) print("axes:") print(ax.get_window_extent().get_points())
[640. 220.8]
figure:
[[ 0. 0.]
[640. 480.]]
axes:
[[350.54545455 52.8 ]
[576. 220.8 ]]
本文转自网络,如有侵权,请联系删除。
学习资源推荐
除了上述分享,如果你也喜欢编程,想通过学习Python获取更高薪资,这里给大家分享一份Python学习资料。
这里给大家展示一下我进的兼职群和最近接单的截图

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
