Настройка графика Networkx (или Scatter) с помощью Python Plotly - PullRequest
0 голосов
/ 28 апреля 2018

Я использую Python-интерфейс Plotly для создания сети. Мне удалось создать сеть с желаемыми узлами и ребрами и контролировать размер узлов. Я отчаянно ищу помощи, как сделать следующее:

  1. добавить метки узлов
  2. добавить метки ребер в соответствии со списком весов
  3. управление шириной линии края в соответствии со списком весов

Все это без использования параметра «зависания», так как оно должно быть в неинтерактивной бумаге. Буду очень признателен за любую помощь! Выход Plotly | В случае неудачи сама фигура | matrix.csv Это мой код (большинство копируется из учебника Plotly для Networkx):

import pandas as pd
import plotly.plotly as py
from plotly.graph_objs import *
import networkx as nx

matrix = pd.read_csv("matrix.csv", sep = "\t", index_col = 0, header = 0)

G = nx.DiGraph()

# add nodes:
G.add_nodes_from(matrix.columns)

# add edges:
edge_lst = [(i,j, matrix.loc[i,j])
            for i in matrix.index
            for j in matrix.columns
            if matrix.loc[i,j] != 0]
G.add_weighted_edges_from(edge_lst)

# create node trace:
node_trace = Scatter(x = [], y = [], text = [], mode = 'markers',
                    marker = Marker(
                    showscale = True,
                    colorscale = 'YIGnBu',
                    reversescale = True,
                    color = [],
                    size = [],
                    colorbar = dict(
                        thickness = 15,
                        title = 'Node Connections',
                        xanchor = 'left',
                        titleside = 'right'),
                    line = dict(width = 2)))

# set node positions
pos = nx.spring_layout(G)
for node in G.nodes():
    G.node[node]['pos']= pos[node]

for node in G.nodes():
    x, y = G.node[node]['pos']
    node_trace['x'].append(x)
    node_trace['y'].append(y)

# create edge trace:
edge_trace = Scatter(x = [], y = [], text = [],
                     line = Line(width = [], color = '#888'),
                     mode = 'lines')

for edge in G.edges():
    x0, y0 = G.node[edge[0]]['pos']
    x1, y1 = G.node[edge[1]]['pos']
    edge_trace['x'] += [x0, x1, None]
    edge_trace['y'] += [y0, y1, None]
    edge_trace['text'] += str(matrix.loc[edge[0], edge[1]])[:5]

# size nodes by degree
deg_dict = {deg[0]:int(deg[1]) for deg in list(G.degree())}
for node, degree in enumerate(deg_dict):
    node_trace['marker']['size'].append(deg_dict[degree] + 20)

fig = Figure(data = Data([edge_trace, node_trace]),
             layout = Layout(
                 title = '<br>AA Substitution Rates',
                 titlefont = dict(size = 16),
                 showlegend = True,
                 margin = dict(b = 20, l = 5, r = 5, t = 40),
                 annotations = [dict(
                     text = "sub title text",
                     showarrow = False,
                     xref = "paper", yref = "paper",
                     x = 0.005, y = -0.002)],
                 xaxis = XAxis(showgrid = False, 
                               zeroline = False, 
                               showticklabels = False),
                 yaxis = YAxis(showgrid = False, 
                               zeroline = False, 
                               showticklabels = False)))

py.plot(fig, filename = 'networkx')

1 Ответ

0 голосов
/ 20 сентября 2018

So

1. Решение этой проблемы относительно простое: вы создаете список с идентификаторами узлов и устанавливаете его в атрибуте text точечной диаграммы. Затем вы устанавливаете режим «маркеры + текст» и все готово.

2. Это немного сложнее. Вы должны рассчитать середину каждой строки и создать список диктов, включая среднюю позицию и вес линии. Затем вы добавляете набор в качестве аннотации макета .

3. Это слишком сложно, чтобы сделать это с помощью сюжетной IMO. На данный момент я вычисляю положение каждого узла с помощью функции networkx spring_layout . Если вы хотите установить ширину каждой строки в зависимости от ее веса, вам нужно изменить положение, используя функцию, которая учитывает все маркеры, к которым прикреплена каждая строка.

Бонус Я даю вам возможность по-разному раскрасить каждый из компонентов графика.

Вот (слегка измененная) функция, которую я сделал недавно, которая выполняет 1 и 2 :

import pandas as pd
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import networkx as nx

def scatter_plot_2d(G, folderPath, name, savePng = False):
    print("Creating scatter plot (2D)...")

    Nodes = [comp for comp in nx.connected_components(G)] # Looks for the graph's communities
    Edges = G.edges()
    edge_weights = nx.get_edge_attributes(G,'weight')

    labels = [] # names of the nodes to plot
    group = [] # id of the communities
    group_cnt = 0

    print("Communities | Number of Nodes")
    for subgroup in Nodes:
        group_cnt += 1
        print("      %d     |      %d" % (group_cnt, len(subgroup)))
        for node in subgroup:
            labels.append(int(node))
            group.append(group_cnt)

    labels, group = (list(t) for t in zip(*sorted(zip(labels, group))))

    layt = nx.spring_layout(G, dim=2) # Generates the layout of the graph
    Xn = [layt[k][0] for k in list(layt.keys())]  # x-coordinates of nodes
    Yn = [layt[k][1] for k in list(layt.keys())]  # y-coordinates
    Xe = []
    Ye = []

    plot_weights = []
    for e in Edges:
        Xe += [layt[e[0]][0], layt[e[1]][0], None]
        Ye += [layt[e[0]][1], layt[e[1]][1], None]
        ax = (layt[e[0]][0]+layt[e[1]][0])/2
        ay = (layt[e[0]][1]+layt[e[1]][1])/2
        plot_weights.append((edge_weights[(e[0], e[1])], ax, ay))

    annotations_list =[
                        dict(   
                            x=plot_weight[1],
                            y=plot_weight[2],
                            xref='x',
                            yref='y',
                            text=plot_weight[0],
                            showarrow=True,
                            arrowhead=7,
                            ax=plot_weight[1],
                            ay=plot_weight[2]
                        ) 
                        for plot_weight in plot_weights
                    ]

    trace1 = go.Scatter(  x=Xe,
                          y=Ye,
                          mode='lines',
                          line=dict(color='rgb(90, 90, 90)', width=1),
                          hoverinfo='none'
                        )

    trace2 = go.Scatter(  x=Xn,
                          y=Yn,
                          mode='markers+text',
                          name='Nodes',
                          marker=dict(symbol='circle',
                                      size=8,
                                      color=group,
                                      colorscale='Viridis',
                                      line=dict(color='rgb(255,255,255)', width=1)
                                      ),
                          text=labels,
                          textposition='top center',
                          hoverinfo='none'
                          )

    xaxis = dict(
                backgroundcolor="rgb(200, 200, 230)",
                gridcolor="rgb(255, 255, 255)",
                showbackground=True,
                zerolinecolor="rgb(255, 255, 255)"
                )
    yaxis = dict(
                backgroundcolor="rgb(230, 200,230)",
                gridcolor="rgb(255, 255, 255)",
                showbackground=True,
                zerolinecolor="rgb(255, 255, 255)"
                )

    layout = go.Layout(
        title=name,
        width=700,
        height=700,
        showlegend=False,
        plot_bgcolor="rgb(230, 230, 200)",
        scene=dict(
            xaxis=dict(xaxis),
            yaxis=dict(yaxis)
        ),
        margin=dict(
            t=100
        ),
        hovermode='closest',
        annotations=annotations_list
        , )
    data = [trace1, trace2]
    fig = go.Figure(data=data, layout=layout)
    plotDir = folderPath + "/"

    print("Plotting..")

    if savePng:
        plot(fig, filename=plotDir + name + ".html", auto_open=True, image = 'png', image_filename=plotDir + name,
         output_type='file', image_width=700, image_height=700, validate=False)
    else:
        plot(fig, filename=plotDir + name + ".html")
...