Python 让多图排版更加美观

一、分析

当有很多幅图的时候,怎样让多图的排版更加美观呢?特别是在不知道图的数量的时候,因为之前玩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这个比例区间,那么看起来就会『神清气爽』,下面列一个表格:

子图总数量行 × 列
11×1
21×2
3:42×2
5:62×3
7:82×4
93×3
10:123×4
13:153×5
164×4
17:183×6
19:204×5
21:244×6
255×5
26:284×7
29:305×6
31:324×8
33:355×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()            

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流浪猪头拯救地球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值