首页 > 解决方案 > 如何创建交互式脑形图?

问题描述

我正在networkxplotly. 有没有办法创建一个类似于人脑外观的 3D 图形,networkx然后将其可视化plotly(因此它将是交互式的)? 在此处输入图像描述

这个想法是让节点在外面(或者只在更容易的情况下显示节点)并像上图一样为一组它们着色

标签: pythonplotlynetworkx

解决方案


首先,这段代码大量借用了 Matteo Mancini,他在此处描述并在 MIT 许可下发布

在原始代码中,没有使用 networkx,因此很明显您实际上并不需要 networkx 来实现您的目标。如果这不是严格的要求,我会考虑使用他的原始代码并对其进行修改以适应您的输入数据。

由于您将 networkx 列为要求,我只是重新编写了他的代码以获取Graph具有某些节点属性的 networkx 对象,例如'color''coord'用于最终散点图中的那些标记特征。我只是选择了数据集中的前十个点来涂成红色,这就是它们没有被分组的原因。

完整的可复制粘贴代码如下。此处的屏幕截图显然不是交互式的,但您可以在 Google Colab 上尝试演示。

Brain_network_plotly_from_networkx


如果在 Linux/Mac 上的 Jupyter notebook 中下载文件:

!wget https://github.com/matteomancini/neurosnippets/raw/master/brainviz/interactive-network/lh.pial.obj
!wget https://github.com/matteomancini/neurosnippets/raw/master/brainviz/interactive-network/icbm_fiber_mat.txt
!wget https://github.com/matteomancini/neurosnippets/raw/master/brainviz/interactive-network/fs_region_centers_68_sort.txt
!wget https://github.com/matteomancini/neurosnippets/raw/master/brainviz/interactive-network/freesurfer_regions_68_sort_full.txt

代码:

import numpy as np
import plotly.graph_objects as go
import networkx as nx # New dependency


def obj_data_to_mesh3d(odata):
    # odata is the string read from an obj file
    vertices = []
    faces = []
    lines = odata.splitlines()   
   
    for line in lines:
        slist = line.split()
        if slist:
            if slist[0] == 'v':
                vertex = np.array(slist[1:], dtype=float)
                vertices.append(vertex)
            elif slist[0] == 'f':
                face = []
                for k in range(1, len(slist)):
                    face.append([int(s) for s in slist[k].replace('//','/').split('/')])
                if len(face) > 3: # triangulate the n-polyonal face, n>3
                    faces.extend([[face[0][0]-1, face[k][0]-1, face[k+1][0]-1] for k in range(1, len(face)-1)])
                else:    
                    faces.append([face[j][0]-1 for j in range(len(face))])
            else: pass
    
    
    return np.array(vertices), np.array(faces)


with open("lh.pial.obj", "r") as f:
    obj_data = f.read()
[vertices, faces] = obj_data_to_mesh3d(obj_data)

vert_x, vert_y, vert_z = vertices[:,:3].T
face_i, face_j, face_k = faces.T

cmat = np.loadtxt('icbm_fiber_mat.txt')
nodes = np.loadtxt('fs_region_centers_68_sort.txt')

labels=[]
with open("freesurfer_regions_68_sort_full.txt", "r") as f:
    for line in f:
        labels.append(line.strip('\n'))

# Instantiate Graph and add nodes (with their coordinates)
G = nx.Graph()

for idx, node in enumerate(nodes):
    G.add_node(idx, coord=node)

# Add made-up colors for the nodes as node attribute
colors_data = {node: ('gray' if node > 10 else 'red') for node in G.nodes}
nx.set_node_attributes(G, colors_data, name="color")

# Add edges
[source, target] = np.nonzero(np.triu(cmat)>0.01)
edges = list(zip(source, target))

G.add_edges_from(edges)

# Get node coordinates from node attribute
nodes_x = [data['coord'][0] for node, data in G.nodes(data=True)]
nodes_y = [data['coord'][1] for node, data in G.nodes(data=True)]
nodes_z = [data['coord'][2] for node, data in G.nodes(data=True)]

edge_x = []
edge_y = []
edge_z = []
for s, t in edges:
    edge_x += [nodes_x[s], nodes_x[t]]
    edge_y += [nodes_y[s], nodes_y[t]]
    edge_z += [nodes_z[s], nodes_z[t]]

# Get node colors from node attribute
node_colors = [data['color'] for node, data in G.nodes(data=True)]

fig = go.Figure()

# Changed color and opacity kwargs
fig.add_trace(go.Mesh3d(x=vert_x, y=vert_y, z=vert_z, i=face_i, j=face_j, k=face_k,
                        color='gray', opacity=0.1, name='', showscale=False, hoverinfo='none'))

fig.add_trace(go.Scatter3d(x=nodes_x, y=nodes_y, z=nodes_z, text=labels,
                           mode='markers', hoverinfo='text', name='Nodes',
                           marker=dict(
                                       size=5, # Changed node size...
                                       color=node_colors # ...and color
                                      )
                           ))
fig.add_trace(go.Scatter3d(x=edge_x, y=edge_y, z=edge_z,
                           mode='lines', hoverinfo='none', name='Edges',
                           opacity=0.3, # Added opacity kwarg
                           line=dict(color='pink') # Added line color
                           ))

fig.update_layout(
    scene=dict(
        xaxis=dict(showticklabels=False, visible=False),
        yaxis=dict(showticklabels=False, visible=False),
        zaxis=dict(showticklabels=False, visible=False),
    ),
    width=800, height=600
)

fig.show()

推荐阅读