如何在python igraph中为顶点标签使用自定义字体?

2 投票
1 回答
1381 浏览
提问于 2025-04-18 09:51

在R的igraph库中,有一种简单的方法可以为图中节点的标签和其他文本设置自定义字体。

plot(G,vertex.label.family="DINPro")

不过我发现,在Python的igraph中,vertex_label_family这个参数是没有的。我花了一些时间找到了一些变通的方法来设置标签的字体,所以我在这里分享我的解决方案。同时我也在想,是否还有更优雅或更简单的解决办法。最开始我尝试在igraph绘图对象的上下文中调用cairo的context.select_font_face(),但可惜的是,igraph.drawing.graph.DefaultGraphDrawer()中的draw()函数在每次plot.redraw()时都会覆盖这个设置。

lo = graph.layout_fruchterman_reingold()
sf = cairo.PDFSurface("test.pdf",1280,1280)
bx = igraph.drawing.utils.BoundingBox(10, 10, 1260, 1260)
plot = igraph.plot(graph,layout=lo,target=sf,bbox=bx)
plot._ctx.select_font_face("DINPro", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
plot.redraw()
plot.save()

所以这个方法不行。我会分享一个简单有效的解决方案。

1 个回答

4

我成功地通过替换一个叫 DefaultGraphDrawer 的类来设置顶点标签的字体。这个新类和原来的类只在两行代码上有所不同。我简单地从我的 Python 安装目录下的 site-packages 文件夹中复制了 igraph/drawing/graph.py 文件,然后删除了除了 DefaultGraphDrawer 以外的所有其他类。在导入部分,我添加了一行代码来导入 AbstractCairoGraphDrawer,并修改了 __all__[] 列表:

from igraph.drawing.graph import AbstractCairoGraphDrawer
__all__ = ["DefaultGraphDrawerFFsupport"]

接着,我重命名了 DefaultGraphDrawer 类,并修改了其中选择字体的部分:

class DefaultGraphDrawerFFsupport(AbstractCairoGraphDrawer):
    ...
    def draw(...):
        ...
        fontFamily = graph.font if hasattr(graph, "font") else "sans-serif"
        context.select_font_face(fontFamily, cairo.FONT_SLANT_NORMAL, \
             cairo.FONT_WEIGHT_NORMAL)
        ...
    ...

我把这个文件(ig_drawing.py)放在我的模块目录里,并进行了导入。这样,我就可以通过将修改后的类作为 drawing_factory 参数传递给 plot() 函数,来设置任何字体:

from ig_drawing import *
lo = graph.layout_fruchterman_reingold()
sf = cairo.PDFSurface("test.pdf",1280,1280)
bx = igraph.drawing.utils.BoundingBox(10, 10, 1260, 1260)
df = igraph.drawing.graph.DefaultGraphDrawer(ctx, bx)
graph.font = "DINPro"
plot = graph.plot(graph,layout=lo,target=sf,bbox=bx,vertex_label=graph.vs["label"],drawer_factory=DefaultGraphDrawerFFsupport)
a.plot.save()

如果你没有设置 graph.font,它会使用默认的 "sans-serif" 字体。不过,如果你提供了一个不存在的字体名称,它会默默地回退到你系统的默认无衬线字体。

看起来默认的 "sans-serif" 字体是硬编码在 igraph 里的,无论是在使用 cairo 表面还是 svg 的绘图函数中。有没有更简单的方法来更改这个呢?

撰写回答