科学强化matplotlib可视化能力

「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

电子书地址:github.com/rougier/sci…

推荐开源技术详解matplotlib的书籍:《scientific-visualization-book》。 主要讲解 Matplotlib 库的介绍与基本原理、图形设计、图形布局与组织、3D 图形与动画等内容。

目录

anatomy of figure

如上图所示,matplotlib图形由多个元素的层次结构组成,这些元素组合在一起形成实际图形,了解图形的不同元素很重要。

元素

Figure

figure最重要的元素是figure本身。它是在调用figure方法时创建的,我们已经看到您可以指定其大小,也可以指定背景色(facecolor)和标题(suptitle)。重要的是要知道,在保存figure时不会使用背景色,因为savefig函数还有一个facecolor参数(默认为白色),该参数将覆盖figure的背景色。如果不需要任何背景,可以在保存figure时指定transparent=True

Axes

Axes是第二个最重要的元素,对应数据实际的呈现区域。它也被称为subplot。每个图形可以有一到多个轴,每个轴通常由称为spines的四条边(左、上、右和下)包围。这些spines中的每一根都可以用major ticksminor ticks(分别指向内部或外部)、tick labelslabel来装饰。

Axis

这些装饰过的spines被称为轴(axis)。水平方向是X轴,垂直方向是Y轴。每一个都由spinemajor ticksminor ticks、主刻度标签和次刻度标签以及轴标签组成。

Spines

spines是连接轴刻度线并标注数据区域边界的线。它们可以放置在任意位置,可以是可见的,也可以是不可见的。

Artist

图形上的一切,包括图形、轴和轴对象,都是artist。包括文字对象、Line2D对象、集合对象、面片对象。渲染人物时,所有artist都被绘制到画布上。给定的artist只能在一个轴上。

渲染

作者对matplotlib的渲染也给出了详细的设置方式

import matplotlib
matplotlib.use("xxx")
复制代码

维度和分辨率

fig = plt.figure(figsize=(6,6))
plt.savefig("output.png")
复制代码

matplotlib的默认dpi为100,该尺寸对应于6英寸乘以6英寸的分辨率。对于一篇 scientific article,出版商通常会要求figures dpi在300到600之间。为了让dpi设置变得正确,我们需要知道在文档中插入图形的物理尺寸是多少。

作者提供了一个更具体的例子,让我们考虑一下这本书的格式是A5(148×210毫米)。左右边距各为20毫米,图像通常使用全文宽度显示。这意味着图像的物理宽度正好为108毫米,或大约为4.25英寸。如果我们使用推荐的600 dpi,我们最终会得到2550 pixels的宽度,这可能超出屏幕分辨率,因此不太方便。相反,当我们在屏幕上显示图形时,我们可以使用默认的 matplotlib dpi(100),只有在保存图形时,我们才使用不同且更高的dpi:

def figure(dpi):
    fig = plt.figure(figsize=(4.25,.2))
    ax = plt.subplot(1,1,1)
    text = "Text rendered at 10pt using %d dpi" % dpi
    ax.text(0.5, 0.5, text, ha="center", va="center",
            fontname="Source Serif Pro",
            fontsize=10, fontweight="light")
    plt.savefig("figure-dpi-%03d.png" % dpi, dpi=dpi)
    
figure(50), figure(100), figure(300), figure(600)
复制代码

作者提供了许多有用的科研作图练习

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

def curve():
    n = np.random.randint(1,5)
    centers = np.random.normal(0.0,1.0,n)
    widths = np.random.uniform(5.0,50.0,n)
    widths = 10*widths/widths.sum()
    scales = np.random.uniform(0.1,1.0,n)
    scales /= scales.sum()
    X = np.zeros(500)
    x = np.linspace(-3,3,len(X))
    for center, width, scale in zip(centers, widths, scales):
        X = X + scale*np.exp(- (x-center)*(x-center)*width)
    return X

np.random.seed(123)
cmap = mpl.cm.get_cmap("Spectral")
fig = plt.figure(figsize=(8, 8))

ax = None
for n in range(3):
    ax = plt.subplot(1, 3, n + 1, frameon=False, sharex=ax)
    for i in range(50):
        Y = curve()
        X = np.linspace(-3, 3, len(Y))
        ax.plot(X, 3 * Y + i, color="k", linewidth=0.75, zorder=100 - i)
        color = cmap(i / 50)
        ax.fill_between(X, 3 * Y + i, i, color=color, zorder=100 - i)

        # Some random text on the right of the curve
        v = np.random.uniform(0, 1)
        if v < 0.4:
            text = "*"
            if v < 0.05:
                text = "***"
            elif v < 0.2:
                text = "**"
            ax.text(
                3.0,
                i,
                text,
                ha="right",
                va="baseline",
                size=8,
                transform=ax.transData,
                zorder=300,
            )

    ax.yaxis.set_tick_params(tick1On=False)
    ax.set_xlim(-3, 3)
    ax.set_ylim(-1, 53)
    ax.axvline(0.0, ls="--", lw=0.75, color="black", zorder=250)
    ax.text(
        0.0,
        1.0,
        "Value %d" % (n + 1),
        ha="left",
        va="top",
        weight="bold",
        transform=ax.transAxes,
    )

    if n == 0:
        ax.yaxis.set_tick_params(labelleft=True)
        ax.set_yticks(np.arange(50))
        ax.set_yticklabels(["Serie %d" % i for i in range(1, 51)])
        for tick in ax.yaxis.get_major_ticks():
            tick.label.set_fontsize(6)
            tick.label.set_verticalalignment("bottom")
    else:
        ax.yaxis.set_tick_params(labelleft=False)


plt.tight_layout()
plt.savefig("./zorder-plots.png", dpi=600)
plt.savefig("./zorder-plots.pdf")
plt.show()
复制代码

参考资料:

[1] Nicolas Rougier. Scientific Visualization: Python + Matplotlib. Nicolas P. Rougier. 2021, 978-2- 9579901-0-8. hal-03427242

猜你喜欢

转载自juejin.im/post/7032284392072413214