Python画图:matplotlib中的5套坐标系统

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()   

入上图所示,当我们想要在轴的左上角画一个图例、文本标签等的时候,就可以用到轴坐标系统,不管xlimylim怎么变化,我们的文本位置都是固定的。

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用轴坐标系统。
不管xlimylim怎么变,我们添加的文本的横坐标都是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学习资料。

这里给大家展示一下我进的兼职群和最近接单的截图

兼职群

私单 😝朋友们如果有需要的话,可以==V扫描下方二维码联系领取==

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

image-20230619144606466

因篇幅有限,仅展示部分资料,添加上方即可获取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值