【问题标题】:Saving a 3D graph generated in Networkx to VTK format for viewing in Paraview将 Networkx 中生成的 3D 图形保存为 VTK 格式,以便在 Paraview 中查看
【发布时间】:2020-07-14 05:36:09
【问题描述】:

我使用以下代码生成了一个 3D 图形网络,并使用 Mayavi 进行可视化。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import networkx as nx
from mayavi import mlab


pos = [[0.1, 2, 0.3], [40, 0.5, -10],
       [0.1, -40, 0.3], [-49, 0.1, 2],
       [10.3, 0.3, 0.4], [-109, 0.3, 0.4]]
pos = pd.DataFrame(pos, columns=['x', 'y', 'z'])

ed_ls = [(x, y) for x, y in zip(range(0, 5), range(1, 6))]

G = nx.Graph()
G.add_edges_from(ed_ls)

nx.draw(G)
plt.show()


# plot 3D in mayavi
edge_size = 0.2
edge_color = (0.8, 0.8, 0.8)
bgcolor = (0, 0, 0)


mlab.figure(1, bgcolor=bgcolor)
mlab.clf()

for i, e in enumerate(G.edges()):
    # ----------------------------------------------------------------------------
    # the x,y, and z co-ordinates are here
    pts = mlab.points3d(pos['x'], pos['y'], pos['z'],
                        scale_mode='none',
                        scale_factor=1)
    # ----------------------------------------------------------------------------
    pts.mlab_source.dataset.lines = np.array(G.edges())
    tube = mlab.pipeline.tube(pts, tube_radius=edge_size)

    mlab.pipeline.surface(tube, color=edge_color)

mlab.show()

我想就如何以 VTK 格式保存这个 3D 图形/如何 将 Networkx 图形对象转换为 VTK 文件,以便在 Paraview 中进行可视化。

编辑: 我已经尝试为输入 Networkx 图调整可用的代码 here 以上分享。但是,我无法获得输出。我只是得到一个空窗口,并且 vtkpolyData 没有绘制在窗口中。

"""
This code converts netwrokx graph to vtk polyData
ref: https://networkx.github.io/documentation/networkx-0.37/networkx.drawing.nx_vtk-pysrc.html
"""

import vtk
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt

from vtk.util.colors import banana, plum


def draw_nxvtk(G, node_pos):
    """
    Draw networkx graph in 3d with nodes at node_pos.

    See layout.py for functions that compute node positions.

    node_pos is a dictionary keyed by vertex with a three-tuple
    of x-y positions as the value.

    The node color is plum.
    The edge color is banana.

    All the nodes are the same size.

    """
    # set node positions
    np={}
    for n in G.nodes():
       try:
           np[n]=node_pos[n]
       except nx.NetworkXError:
           print("node %s doesn't have position"%n)

    nodePoints = vtk.vtkPoints()

    i=0
    for (x,y,z) in np.values():
       nodePoints.InsertPoint(i, x, y, z)
       i=i+1

    # Create a polydata to be glyphed.
    inputData = vtk.vtkPolyData()
    inputData.SetPoints(nodePoints)

    # Use sphere as glyph source.
    balls = vtk.vtkSphereSource()
    balls.SetRadius(.05)
    balls.SetPhiResolution(20)
    balls.SetThetaResolution(20)

    glyphPoints = vtk.vtkGlyph3D()
    glyphPoints.SetInputData(inputData)
    glyphPoints.SetSourceData(balls.GetOutput())

    glyphMapper = vtk.vtkPolyDataMapper()
    glyphMapper.SetInputData(glyphPoints.GetOutput())

    glyph = vtk.vtkActor()
    glyph.SetMapper(glyphMapper)
    glyph.GetProperty().SetDiffuseColor(plum)
    glyph.GetProperty().SetSpecular(.3)
    glyph.GetProperty().SetSpecularPower(30)

    # Generate the polyline for the spline.
    points = vtk.vtkPoints()
    edgeData = vtk.vtkPolyData()

    # Edges

    lines = vtk.vtkCellArray()
    i = 0
    for e in G.edges():
        # The edge e can be a 2-tuple (Graph) or a 3-tuple (Xgraph)
        u = e[0]
        v = e[1]
        if v in node_pos and u in node_pos:
            lines.InsertNextCell(2)
            for n in (u, v):
                (x, y, z) = node_pos[n]
                points.InsertPoint(i, x, y, z)
                lines.InsertCellPoint(i)
                i = i+1

    edgeData.SetPoints(points)
    edgeData.SetLines(lines)

    # Add thickness to the resulting line.
    Tubes = vtk.vtkTubeFilter()
    Tubes.SetNumberOfSides(16)
    Tubes.SetInputData(edgeData)
    Tubes.SetRadius(.01)
    #
    profileMapper = vtk.vtkPolyDataMapper()
    profileMapper.SetInputData(Tubes.GetOutput())

    #
    profile = vtk.vtkActor()
    profile.SetMapper(profileMapper)
    profile.GetProperty().SetDiffuseColor(banana)
    profile.GetProperty().SetSpecular(.3)
    profile.GetProperty().SetSpecularPower(30)

    # Now create the RenderWindow, Renderer and Interactor
    ren = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(ren)

    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    # Add the actors
    ren.AddActor(glyph)
    ren.AddActor(profile)

    renWin.SetSize(640, 640)

    iren.Initialize()
    renWin.Render()
    iren.Start()


if __name__ == "__main__":

    pos = [[0.1, 2, 0.3], [40, 0.5, -10],
           [0.1, -40, 0.3], [-49, 0.1, 2],
           [10.3, 0.3, 0.4], [-109, 0.3, 0.4]]
    pos = pd.DataFrame(pos, columns=['x', 'y', 'z'])
    pos_d = pos.T.to_dict(orient='list')
    
    ed_ls = [(x, y) for x, y in zip(range(0, 5), range(1, 6))]

    G = nx.Graph()
    G.add_edges_from(ed_ls)
    # nx.draw(G, with_labels=True, pos=nx.spring_layout(G))
    # plt.show()
    draw_nxvtk(G=G, node_pos=pos_d)

关于如何在运行上述代码时查看显示的 polyData 输出以及如何保存 vtkPolyData 以在 Paraview 中导入的建议将非常有帮助。

【问题讨论】:

标签: networkx vtk mayavi paraview graph-visualization


【解决方案1】:

如果您可以使用构建在 vtk 之上的 vedo,这将变得很容易:

import networkx as nx

pos = [[0.1, 2, 0.3],    [40, 0.5, -10],
       [0.1, -40, 0.3],  [-49, 0.1, 2],
       [10.3, 0.3, 0.4], [-109, 0.3, 0.4]]

ed_ls = [(x, y) for x, y in zip(range(0, 5), range(1, 6))]

G = nx.Graph()
G.add_edges_from(ed_ls)
nxpos = nx.spring_layout(G)
nxpts = [nxpos[pt] for pt in sorted(nxpos)]
# nx.draw(G, with_labels=True, pos=nxpos)
# plt.show()

raw_lines = [(pos[x],pos[y]) for x, y in ed_ls]
nx_lines = []
for x, y in ed_ls:
    p1 = nxpos[x].tolist() + [0] # add z-coord
    p2 = nxpos[y].tolist() + [0]
    nx_lines.append([p1,p2])

from vedo import *
raw_pts = Points(pos, r=12)
raw_edg = Lines(raw_lines).lw(2)
show(raw_pts, raw_edg, raw_pts.labels('id'),
     at=0, N=2, axes=True, sharecam=False)

nx_pts = Points(nxpts, r=12)
nx_edg = Lines(nx_lines).lw(2)
show(nx_pts, nx_edg, nx_pts.labels('id'),
     at=1, interactive=True)

write(nx_edg, 'afile.vtk') # save the lines

该包还支持 DirectedGraphs,因此第二个选项是:

from vedo import *
from vedo.pyplot import DirectedGraph

# Layouts: [2d, fast2d, clustering2d, circular, circular3d, cone, force, tree]
g = DirectedGraph(layout='fast2d')
g.arrowScale =0.1
for i in range(6): g.addChild(i)
g.build()
show(g, axes=1)

write(g.unpack(0), 'afile.vtk')

编辑:跟进请求,

如何使用cellColors() 包含基于标量的线条颜色映射:

# ... from the first example

from vedo import *
raw_pts = Points(pos, r=12)
raw_edg = Lines(raw_lines).lw(3)

nx_pts = Points(nxpts, r=12).c('red').alpha(0.5)
nx_edg = Lines(nx_lines).lw(2)

v1 = [sin(x)  for x in range(6)]
v2 = [sqrt(x) for x in range(6)]
vc = [x for x in range(nx_edg.NCells())]
labs1 = nx_pts.labels(v1, scale=.05).c('green').addPos(0.02,.04,0)
labs2 = nx_pts.labels(v2, scale=.05).c('red').addPos(0.02,-.04,0)
labsc = nx_edg.labels(vc, cells=True, scale=.04, precision=1, rotZ=-45)
labsc.c('black')

nx_edg.cellColors(vc, cmap='viridis').addScalarBar3D(c='k').addPos(.2,0,0)
# nx_edg.cellColors(vc, cmap='jet').addScalarBar() # this is a 2D scalarbar

show(nx_pts, nx_edg, labs1, labs2, labsc, axes=1)

如何用鼠标悬停点以弹出带有flag()的标志消息:

from vedo import *
raw_pts = Points(pos, r=12)
raw_edg = Lines(raw_lines).lw(3)

nx_pts = []
for p in nxpts:
    ap = Point(p, r=20).c('red').alpha(0.5)
    ap.flag('some text:\n'+'x='+precision(p[0],2)+'\ny='+precision(p[1],2))
    nx_pts.append(ap)

nx_edg = Lines(nx_lines).lw(3)
show(nx_pts, nx_edg, axes=1)

如何将线条颜色插入节点值:

(注意:这里clean() 删除了重复点,所以请仔细检查可能与初始数组不匹配的点)

from vedo import *

nx_pts = Points(nxpts, r=12).c('grey').alpha(0.5)
nx_edg = Lines(nx_lines).lw(5)

v1 = [sin(x) for x in range(6)]
labs1 = nx_pts.labels(v1, scale=.05).c('green').addPos(0.02,.04,0)

nx_edg.clean().pointColors(v1, cmap='viridis').addScalarBar()

show(nx_pts, nx_edg, labs1, axes=1)

【讨论】:

  • 非常感谢。这有帮助!我可以再问一个问题吗?我有对应于上述图中每个节点的值(时间序列数据),我想使用插值器在两个节点之间插值并随着时间的推移对其进行动画处理。我想知道这是否可以在 vedo 中完成和可视化(我在 github repo 上看到了几个示例,但我找不到此类示例)。我可以加载与 np 数组中每个节点对应的时间序列数据。我不知道如何从这里拿走它。
  • 作为我最初问题的后续,我想知道如何显示节点属性。例如,`raw_pts.labels('id'),` 显示节点 ID。我想知道是否可以显示节点的附加属性?
  • 哦.. 尝试在 show() 中添加 interactive=True。请注意,您可以通过添加偏移量来修改标签的位置:mylabels = raw_pts.labels([2.0,2.1,2.2,2.3,2.4,2.5]).addPos(0,-1,0)
  • 是的,您可以这样做 - 请查看更新后的答案。
  • 在这种情况下,再次检查更新的答案和警告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 1970-01-01
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
  • 2023-01-08
  • 1970-01-01
相关资源
最近更新 更多