image.png
电子书地址:https://github.com/rougier/scientific-visualization-book

一本科学详解matplotlib的可视化书籍

目录

image.png

anatomy of figure

image.png

如上图所示,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只能在一个轴上。

image.png

渲染

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

  1. import matplotlib
  2. matplotlib.use("xxx")

image.png
image.png

维度和分辨率

  1. fig = plt.figure(figsize=(6,6))
  2. plt.savefig("output.png")

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

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

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

image.png

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

  1. import numpy as np
  2. import matplotlib as mpl
  3. import matplotlib.pyplot as plt
  4. def curve():
  5. n = np.random.randint(1,5)
  6. centers = np.random.normal(0.0,1.0,n)
  7. widths = np.random.uniform(5.0,50.0,n)
  8. widths = 10*widths/widths.sum()
  9. scales = np.random.uniform(0.1,1.0,n)
  10. scales /= scales.sum()
  11. X = np.zeros(500)
  12. x = np.linspace(-3,3,len(X))
  13. for center, width, scale in zip(centers, widths, scales):
  14. X = X + scale*np.exp(- (x-center)*(x-center)*width)
  15. return X
  16. np.random.seed(123)
  17. cmap = mpl.cm.get_cmap("Spectral")
  18. fig = plt.figure(figsize=(8, 8))
  19. ax = None
  20. for n in range(3):
  21. ax = plt.subplot(1, 3, n + 1, frameon=False, sharex=ax)
  22. for i in range(50):
  23. Y = curve()
  24. X = np.linspace(-3, 3, len(Y))
  25. ax.plot(X, 3 * Y + i, color="k", linewidth=0.75, zorder=100 - i)
  26. color = cmap(i / 50)
  27. ax.fill_between(X, 3 * Y + i, i, color=color, zorder=100 - i)
  28. # Some random text on the right of the curve
  29. v = np.random.uniform(0, 1)
  30. if v < 0.4:
  31. text = "*"
  32. if v < 0.05:
  33. text = "***"
  34. elif v < 0.2:
  35. text = "**"
  36. ax.text(
  37. 3.0,
  38. i,
  39. text,
  40. ha="right",
  41. va="baseline",
  42. size=8,
  43. transform=ax.transData,
  44. zorder=300,
  45. )
  46. ax.yaxis.set_tick_params(tick1On=False)
  47. ax.set_xlim(-3, 3)
  48. ax.set_ylim(-1, 53)
  49. ax.axvline(0.0, ls="--", lw=0.75, color="black", zorder=250)
  50. ax.text(
  51. 0.0,
  52. 1.0,
  53. "Value %d" % (n + 1),
  54. ha="left",
  55. va="top",
  56. weight="bold",
  57. transform=ax.transAxes,
  58. )
  59. if n == 0:
  60. ax.yaxis.set_tick_params(labelleft=True)
  61. ax.set_yticks(np.arange(50))
  62. ax.set_yticklabels(["Serie %d" % i for i in range(1, 51)])
  63. for tick in ax.yaxis.get_major_ticks():
  64. tick.label.set_fontsize(6)
  65. tick.label.set_verticalalignment("bottom")
  66. else:
  67. ax.yaxis.set_tick_params(labelleft=False)
  68. plt.tight_layout()
  69. plt.savefig("./zorder-plots.png", dpi=600)
  70. plt.savefig("./zorder-plots.pdf")
  71. plt.show()

image.png

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