在 python 中是否有一种有效的方法可以将 2D 图存储为矢量图形?

Is there an efficient way to store 2D plots as a vector graphic in python?

我目前正在尝试将 python 图存储为矢量图形以改善它们在乳胶文档中的外观。对于一维图,这非常有效:

import numpy as np
import matplotlib as mpl
mpl.use('svg')
new_rc_params = {
    "font.family": 'Times',
    "font.size": 12,
    "font.serif": [],
    "svg.fonttype": 'none'} #to store text as text, not as path
mpl.rcParams.update(new_rc_params)
import matplotlib.pyplot as plt

x = np.linspace(-.5, .5, 1024)

plt.figure()
plt.plot(x, x)
plt.title('$x = y$')
plt.xlabel('$x$ [m]')
plt.ylabel('$y$ [m]')
plt.savefig('test.svg', format = 'svg', bbox_inches = 'tight')

这样我可以在 inkscape 中打开 svg 文件并将其转换为 pdf/pdf_tex 并且绘图中的每个文本都将在文档中以乳胶呈现 --> 与文档中其他地方相同的字体和字体大小文件.

2D 图变得像 svg 文件一样大。因此,我想将绘图存储为 pdf(同样,我想将文本保留为文本。这就是我不能将绘图存储为 .png 的原因):

mpl.use('pdf')
new_rc_params = {
    "font.family": 'Times',
    "font.size": 12,
    "font.serif": []
    }
    #"svg.fonttype": 'none'} #not needed here since we don't use svg anymore
mpl.rcParams.update(new_rc_params)
import matplotlib.pyplot as plt

x = np.linspace(-.5, .5, 1024)
x, y = np.meshgrid(x, x)
z = np.exp(-(x**2 + y**2))

plt.figure()
plt.title('Gaussian plot: $z = \exp{-(x^2 + y^2)}$')
plt.pcolormesh(x, y, z)
plt.colorbar()
plt.savefig('test.pdf', bbox_inches='tight', format='pdf')

这会将 2D 图存储为 pdf。无论如何,现在存储绘图需要一段时间,而且它变得非常大(即使绘图中只有 500 x 500 点,它也大约为 11 MB)。但是,文本存储为文本。

不幸的是,我现在无法在inkscape 中打开pdf,因为它总是在一段时间后崩溃。可能文件已经太大了。有什么建议么?在这种情况下进一步下采样可能有效,但一般情况下可能无效。

这是我在评论中建议的答案:

大型 pdf/svg 文件是将每个矩形存储在 pcolormesh 中作为矢量图形生成的。

我想通过将绘图存储为 svg/pdf 来实现的目的是获得高分辨率图像,一旦我将文件插入我的乳胶文档中,就会呈现文本。如果分辨率足够好,绘图本身并不需要是矢量图形。

所以这是我的建议(导入库同上):

mpl.use('svg')
new_rc_params = {
    "font.family": 'Times', #probably python doesn't know Times, but it will replace it with a different font anyway. The final decision is up to the latex document anyway
    "font.size": 12, #choosing the font size helps latex to place all the labels, ticks etc. in the right place
    "font.serif": [],
    "svg.fonttype": 'none'} #to store text as text, not as path
mpl.rcParams.update(new_rc_params)

plt.figure(figsize = (6.49/2, 6.49/2)) #that's about half the text width of an A4 document
plt.pcolormesh(x, y, z, rasterized = True) # That's the trick. It will render the image already in python!
plt.xlabel('Math expression: $a + b = c$') # We need the backslashes because otherwise python will render the mathematic expression which will confuse latex
plt.savefig('test.svg', dpi = 1000, format = 'svg', bbox_inches = 'tight') # depends on your final figure size, 1000 dpi should be definitely enough for A4 documents

存储 svg 文件后,在 Inkscape 中打开它。另存为 pdf 并将勾号设置为 'Omit text in PDF and create LaTex file'。在你的乳胶文件中你必须使用

\begin{figure}
    \centering
    \input{test.pdf_tex}
    \caption{This should have the same font type and size as your xlabel}
\end{figure}

导入您的 2D 图。就是这样:)