Matplotlib SVG 滤镜线条

Beginner

This tutorial is from open-source community. Access the source code

简介

本实验演示如何在 Matplotlib 中使用 SVG 过滤效果。只有当你的 SVG 渲染器支持时,过滤效果才会有效。

虚拟机使用提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签,以访问 Jupyter Notebook 进行练习。

有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。

如果你在学习过程中遇到问题,随时向 Labby 提问。课程结束后提供反馈,我们会及时为你解决问题。

导入所需库

首先,我们需要导入所需的库:matplotlib.pyplotioxml.etree.ElementTree

import io
import xml.etree.ElementTree as ET
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

创建图形和坐标轴

我们使用 plt.figure() 创建一个图形对象,并使用 fig1.add_axes() 添加一个坐标轴对象。我们还使用 [0.1, 0.1, 0.8, 0.8] 设置坐标轴的大小和位置。

fig1 = plt.figure()
ax = fig1.add_axes([0.1, 0.1, 0.8, 0.8])

绘制线条

我们使用 ax.plot() 绘制两条线。我们还使用不同的颜色、标记和标签对线条进行定制。

l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-", mec="b", lw=5, ms=10, label="Line 1")
l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "rs-", mec="r", lw=5, ms=10, label="Line 2")

绘制阴影

我们通过使用与原线条稍有偏移且为灰色的相同线条来为线条绘制阴影。我们调整阴影线条的颜色和 z 轴顺序,使其绘制在原始线条下方。我们还使用 offset_copy() 方法为阴影线条创建一个偏移变换。

for l in [l1, l2]:
    xx = l.get_xdata()
    yy = l.get_ydata()
    shadow, = ax.plot(xx, yy)
    shadow.update_from(l)

    shadow.set_color("0.2")
    shadow.set_zorder(l.get_zorder() - 0.5)

    transform = mtransforms.offset_copy(l.get_transform(), fig1, x=4.0, y=-6.0, units='points')
    shadow.set_transform(transform)

    shadow.set_gid(l.get_label() + "_shadow")

设置坐标轴范围并保存图形

我们设置坐标轴的 x 和 y 范围,并使用 io.BytesIO()plt.savefig() 将图形保存为 SVG 格式的字节字符串。

ax.set_xlim(0., 1.)
ax.set_ylim(0., 1.)

f = io.BytesIO()
plt.savefig(f, format="svg")

定义滤镜

我们使用带有 stdDeviation 属性的 <defs><filter> 标签来定义高斯模糊滤镜。

filter_def = """
  <defs xmlns='http://www.w3.org/2000/svg'
        xmlns:xlink='http://www.w3.org/1999/xlink'>
    <filter id='dropshadow' height='1.2' width='1.2'>
      <feGaussianBlur result='blur' stdDeviation='3'/>
    </filter>
  </defs>
"""

读取并修改 SVG

我们使用 ET.XMLID() 读取保存的 SVG,并使用 tree.insert() 将滤镜定义插入到 SVG DOM 树中。然后,我们通过给定的 ID 获取 SVG 元素,并使用 shadow.set() 应用阴影滤镜。

tree, xmlid = ET.XMLID(f.getvalue())

tree.insert(0, ET.XML(filter_def))

for l in [l1, l2]:
    shadow = xmlid[l.get_label() + "_shadow"]
    shadow.set("filter", 'url(#dropshadow)')

fn = "svg_filter_line.svg"
print(f"Saving '{fn}'")
ET.ElementTree(tree).write(fn)

总结

本实验展示了如何在 Matplotlib 中使用 SVG 过滤效果。我们学习了如何创建图形和坐标轴、绘制线条和阴影、设置坐标轴范围,以及定义并将滤镜应用于 SVG。