Matplotlib SVG输出与实际SVG坐标

dy1byipe  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(164)

我有一个SVG格式的大矢量图形,我想用matplotlib将其绘制成。为此,我创建matplotlib图,将其存储为SVG,然后合并文件。但是,matplotlib使用的坐标与我的主SVG文件的坐标不匹配。
为了找到我想要绘制的对象的位置,我使用了它的idtranslate属性(如果需要的话,递归地),例如:
如果我想画出X的位置

<?xml version="1.0" encoding="UTF-8"?>
<svg width="2283px" height="1252px" viewBox="0 0 300 300" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    
    <g xmlns="http://www.w3.org/2000/svg" id="X" 
      transform="translate(10.0, 20.0)" fill-rule="nonzero">
        <circle id="circle" stroke="#FF5252" stroke-width="2" fill="#FFFFFF" cx="4" cy="4" r="4"/>
    </g>
</svg>

我使用以下代码绘制为(10,20):

import matplotlib as mpl
import matplotlib.pyplot as plt

# set the backend to SVG, 
# according to https://stackoverflow.com/questions/70759115/text-position-changes-when-a-matplotlib-figure-is-saved-in-svg
mpl.use('svg')  

fig, ax = plt.subplots(1, 1, squeeze=True)
plt.axis('off')

# print to the location of "X"
ax.scatter([10], [20])

# needs to be done according to 
# https://stackoverflow.com/questions/24525111/how-can-i-get-the-output-of-a-matplotlib-plot-as-an-svg
# otherwise the produced output is not in a visible bound
plt.gca().set_position([0, 0, 1, 1])
plt.savefig('/tmp/test.svg', backend='svg', format='svg', transparent=True)

但输出具有偏移量并被缩放。
结果:
红色圆圈来自原始SVG,蓝色点来自matplotlib。

请注意,我将SVG对象“X”放入“/tmp/test.svg”的主体中

ruyhziif

ruyhziif1#

您应该注意图形的大小和绘制元素的坐标。
一旦你修复了这些值,你应该反转mpl图的y轴(在mpl中y是从下到上,在svg中y是从上到下)。
简单的例子,将原始svg的大小调整为viewBox(1px=0.75pt参见there):

<?xml version="1.0" encoding="UTF-8"?>
<svg width="400px" height="400px" viewBox="0 0 300 300" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    
    <g xmlns="http://www.w3.org/2000/svg" id="X" 
      transform="translate(10.0, 20.0)" fill-rule="nonzero">
        <circle id="circle" stroke="#FF5252" stroke-width="2" fill="#FFFFFF" cx="4" cy="4" r="4"/>
    </g>
    
</svg>

svg后端的dpi似乎是 * 硬编码 * 为72(参见mpl源代码)。因此,您将使用以下代码获得拟合坐标:

import matplotlib.pyplot as plt

dpi = 72 # default for svg backend
width_in_pt = 300
height_in_pt = 300

fig, ax = plt.subplots(1, 1, figsize=[width_in_pt/dpi,height_in_pt/dpi], dpi=dpi)
plt.axis('off')

# print to the location of "X"
ax.scatter([14], [24])  # coordinates are 10+4 (x-translation + cx) and 20+4 (y-translation + cy)
ax.set_xlim([0, width_in_pt])
ax.set_ylim([0, height_in_pt])
ax.invert_yaxis()

fig.subplots_adjust(bottom=0, top=1, left=0, right=1)
plt.savefig('test_mpl.svg', backend='svg', transparent=True)

编辑:我把pt和px搞混了,用更清晰的方式重写了答案

相关问题