一、分析
当有很多幅图的时候,怎样让多图的排版更加美观呢?特别是在不知道图的数量的时候,因为之前玩Matlab的时候,遇到过类似的问题(Matlab 让多图排版更美观),所以笔者有充足的信心可以得到让自己满意的答案,下面一起来研究一下。
1、分辨率
我们的电脑一般横竖分辨率为
它们的比例一般为1:1~1:2
其实范围更小,并且电脑屏幕的物理横竖比为16:9=1.78:1
(通常所说的电脑尺寸就是对角线的长度,1英寸=2.54厘米)。另外这里补充一点DPI的知识:
- DPI(Dots Per Inch,每英寸点数)是一个量度单位,用于点阵数码影像,指每一英寸长度中,取样、可显示或输出点的数目。
- 鼠标的DPI:每英寸鼠标采样次数。明白讲,就是鼠标移动一英寸,鼠标自己能够从移动表面上采集到多少个点的变化。
- 显示器DPI:每英寸像素点的个数,比如我的屏幕分辨率为
2560*1440
,屏幕物理尺寸为14寸=6.86寸*12.2寸
,那么我横竖每寸像素点的个数均为275
,即我的显示器DPI为275
- 图像DPI:图像的DPI的含义是每寸的像素数,web上的图片一般都是72DPI,DPI越高,扫描清晰度越高,一般照片冲洗必须为300+DPI
- 印刷DPI:DPI原来是印刷上的记量单位,意思是每英寸上,所能印刷的网点数(Dot Per Inch)。但随着数字输入,输出设备快速发展,大多数的人也将数字影像的解析度用DPI表示,但较为严谨的人可能注意到,印刷时计算的网点(Dot)和电脑显示器的显示像素(Pixel)并非相同,所以较专业的人士,会用PPI(Pixel Per Inch)表示数字影像的解析度,以区分二者。
- 4k 影视:横向像素数有几个1024就称为几k,4k就是一行有
4096
个像素点,我们通常看的高清电影的分辨率也就1920×1080
2、子图排布
所以,如果将横竖子图个数的比例控制在1:1~1:2
这个比例区间,那么看起来就会『神清气爽』,下面列一个表格:
子图总数量 | 行 × 列 |
---|---|
1 | 1×1 |
2 | 1×2 |
3:4 | 2×2 |
5:6 | 2×3 |
7:8 | 2×4 |
9 | 3×3 |
10:12 | 3×4 |
13:15 | 3×5 |
16 | 4×4 |
17:18 | 3×6 |
19:20 | 4×5 |
21:24 | 4×6 |
25 | 5×5 |
26:28 | 4×7 |
29:30 | 5×6 |
31:32 | 4×8 |
33:35 | 5×7 |
这个表格的处理可能也并不是特别好,暂且就这么搞。并且,一幅图中的子图数量不可能一直变多,实在不行就搞两张,三张,干嘛非得挤到一起!
3、常用的绘图语句
笔者在 Python 中绘图经常使用的一句话如下:
fig=plt.figure(figsize=(12,6),dpi=100,facecolor='w')
其中
- figuresize 控制的是图像的大小,它的单位为英寸,
12,6
代表图像宽12英寸,高12英寸 - dpi就是指图像的分辨率,上面已经有所解释,即每英寸像素点的个数,它的值越大,代表图像越清晰,相应的保存下来图像的大小也越大
- facecolor 图的底色
还有其他的语句:
# 控制坐标轴上小短线的大小和方向,控制坐标轴刻度标注的大小
ax1.tick_params(axis='both', colors='black', direction='out', labelsize=15, width=1, length=1, pad=5)
二、代码实现过程
首先根据子图总数量确定行列数:
def nfigure2ab(num):
"""
get the number of row and cloum according to the number of sub-figure
> @param[in] num: the number of sub-figure
return:
< @param[out] a the number of the row
< @param[out] b the number of the cloum
"""
if num==1:
a=1;b=1
elif num==2:
a=1;b=2
elif num>2 and num<=4:
a=2;b=2
elif num>4 and num<=6:
a=2;b=3
elif num>6 and num<=8:
a=2;b=4
elif num==9:
a=3;b=3
elif num>9 and num<=12:
a=3;b=4
elif num>12 and num<=15:
a=3;b=5
elif num==16:
a=4;b=4
elif num>16 and num<=18:
a=3;b=6
elif num>18 and num<=20:
a=4;b=5
elif num>21 and num<=24:
a=4;b=6
elif num==25:
a=5;b=5
elif num>25 and num<=28:
a=4;b=7
elif num>28 and num<=30:
a=5;b=6
elif num>30 and num<=32:
a=4;b=8
elif num>32 and num<=35:
a=5;b=7
else:
print('The number is too large!')
a=0;b=0
return a,b
根据上面的小函数暂且画一下:
def test(num):
a,b=nfigure2ab(num)
fig=plt.figure(figsize=(12,6),dpi=100,facecolor='w')
for i in range(num):
plt.subplot(a, b, i+1)
test(15)
plt.show()
看起来还可以,这个比Matlab要好多了,Matlab子图与子图之间的间距非常大,还得人为去调整。虽然Python不用调整间距,但是它还有一些其他问题,比如:刻度字体太小,子图之间不想让显示刻度,只让边缘的子图显示刻度和刻度标注。经过一番改良,代码如下:
def test(num):
a,b=nfigure2ab(num)
fig=plt.figure(figsize=(12,6),dpi=100,facecolor='w')
for i in range(num):
ax=plt.subplot(a, b, i+1)
ax.tick_params(axis='both', colors='black', direction='out', labelsize=15, width=1, length=1, pad=5)
if math.ceil((i+1)/b)!=a:
plt.xticks([])
if i%b!=0:
plt.yticks([])
test(15)
plt.show()
至此,大功告成
三、实验结果
这部分对第二部分精简一下,将得到的结论(结果)汇总整理,以便以后快速使用。
def nfigure2ab(num):
"""
get the number of row and cloum according to the number of sub-figure
> @param[in] num: the number of sub-figure
return:
< @param[out] a the number of the row
< @param[out] b the number of the cloum
"""
if num==1:
a=1;b=1
elif num==2:
a=1;b=2
elif num>2 and num<=4:
a=2;b=2
elif num>4 and num<=6:
a=2;b=3
elif num>6 and num<=8:
a=2;b=4
elif num==9:
a=3;b=3
elif num>9 and num<=12:
a=3;b=4
elif num>12 and num<=15:
a=3;b=5
elif num==16:
a=4;b=4
elif num>16 and num<=18:
a=3;b=6
elif num>18 and num<=20:
a=4;b=5
elif num>21 and num<=24:
a=4;b=6
elif num==25:
a=5;b=5
elif num>25 and num<=28:
a=4;b=7
elif num>28 and num<=30:
a=5;b=6
elif num>30 and num<=32:
a=4;b=8
elif num>32 and num<=35:
a=5;b=7
else:
print('The number is too large!')
a=0;b=0
return a,b
def test(num):
a,b=nfigure2ab(num)
fig=plt.figure(figsize=(12,6),dpi=100,facecolor='w')
for i in range(num):
ax=plt.subplot(a, b, i+1)
ax.tick_params(axis='both', colors='black', direction='out', labelsize=15, width=1, length=1, pad=5)
if math.ceil((i+1)/b)!=a:
plt.xticks([])
if i%b!=0:
plt.yticks([])
test(15)
plt.show()