dirtyw0lf
dirtyw0lf

Reputation: 1958

Plotting a directed graph with Dash through Matplotlib

It seems Dash is unable to process directed network graphs via plotly. So I am going through Matplotlib to render the graph using mpl_to_plotly. A graph does render on the site, but without the edges, and there is the following console output:

Dang! That path collection is out of this world. I totally don't know what to do with it yet! Plotly can only import path collections linked to 'data' coordinates

Matplotlib code

mpl_fig , ax = plt.subplots()

G = nx.Graph()

G.add_edge('a', 'b', weight=0.6)
G.add_edge('a', 'c', weight=0.2)
G.add_edge('c', 'd', weight=0.1)
G.add_edge('c', 'e', weight=0.7)
G.add_edge('c', 'f', weight=0.9)
G.add_edge('a', 'd', weight=0.3)

elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] <= 0.5]

pos = nx.spring_layout(G)  # positions for all nodes

# nodes
nx.draw_networkx_nodes(G, pos, node_size=700)

# edges
nx.draw_networkx_edges(G, pos, edgelist=elarge,
                       width=6)
nx.draw_networkx_edges(G, pos, edgelist=esmall,
                       width=6, alpha=0.5, edge_color='b', style='dashed')

# labels
nx.draw_networkx_labels(G, pos, font_size=20, font_family='sans-serif')


# error with plotly no supporting this kind of thing. Ty exporting to image and just show the image. Sucks becaues it is not interactive... but at least im showing what I want. 

print(pos)

#plt.show()

plotly_fig = mpl_to_plotly(mpl_fig)

called in Dash via

dcc.Graph(id='network-graph', figure=plotly_fig)

Is there another method to process network directed graphs in Dash? Or another way to use the matplotlib technique?

Upvotes: 1

Views: 2222

Answers (1)

Renat
Renat

Reputation: 8962

There is an opened issue in Plotly that mpl_to_ploty doesn't work with draw_networkx_edges (link).

Also Plotly doesn't natively support directed edges (link), they might be simulated with arrows from annotations though.

Given that graph figure might be constructed manually with Plotly syntax, e.g. as (without Matplotlib):

import networkx as nx
import dash
import dash_core_components as dcc
import dash_html_components as html

G = nx.DiGraph()

G.add_edge('a', 'b', weight=0.6)
G.add_edge('a', 'c', weight=0.2)
G.add_edge('c', 'd', weight=0.1)
G.add_edge('c', 'e', weight=0.7)
G.add_edge('c', 'f', weight=0.9)
G.add_edge('a', 'd', weight=0.3)

elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] <= 0.5]

pos = nx.spring_layout(G)  # positions for all nodes


Xn=[pos[k][0] for k in pos]
Yn=[pos[k][1] for k in pos]
labels = [k for k in pos]

nodes=dict(type='scatter',
           x=Xn, 
           y=Yn,
           mode='markers+text',
           marker=dict(size=28, color='rgb(31,120,180)'),
           textfont=dict(size=22, color='#DBD700'),
           text=labels,
           hoverinfo='text')

Xaxis=dict(showline=False, zeroline=False, showgrid=False, showticklabels=True,
          mirror='allticks', ticks='inside', ticklen=5, tickfont = dict(size=14),
          title='')

Yaxis=dict(showline=False, zeroline=False, showgrid=False, showticklabels=True,
          mirror='allticks', ticks='inside', ticklen=5, tickfont = dict(size=14), 
          title='')

annotateELarge = [ dict(showarrow=True, arrowsize=0.9, arrowwidth=6, arrowhead=5, standoff=14, startstandoff=4,
                         ax=pos[arrow[0]][0], ay=pos[arrow[0]][1], axref='x', ayref='y',
                         x=pos[arrow[1]][0], y=pos[arrow[1]][1], xref='x', yref='y'
                        ) for arrow in elarge]
annotateESmall = [ dict(showarrow=True, arrowsize=1.5, arrowwidth=2, arrowhead=5, opacity=0.5, standoff=14, startstandoff=4,
                        ax=pos[arrow[0]][0], ay=pos[arrow[0]][1], axref='x', ayref='y',
                        x=pos[arrow[1]][0], y=pos[arrow[1]][1], xref='x', yref='y'
                        ) for arrow in esmall]

layout=dict(width=800, height=600,
            showlegend=False,
            xaxis=Xaxis,
            yaxis=Yaxis,
            hovermode='closest',
            plot_bgcolor='#E5ECF6',
            annotations= annotateELarge + annotateESmall, #arrows
            )

plotly_fig = dict(data=[nodes], layout=layout)


#Dash page stub
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(children=[
    dcc.Graph(id='network-graph', figure=plotly_fig)
])

if __name__ == '__main__':
    app.run_server(debug=True)

Upvotes: 2

Related Questions