casparschwa
casparschwa

Reputation: 55

Plot networkx graph with hierachy horizontally and manipulate length of arrows

I am struggling to produce a plot that I want to get. I create a networkx graph with a model of mine. To get the hierachical display of nodes I used graphviz_layout. I managed to color code the nodes like I want to, but a few things I cannot get to work:

This is my code...

from networkx.drawing.nx_agraph import write_dot, graphviz_layout

G = model.block_tree.tree
write_dot(G,'test.dot')
pos = graphviz_layout(G, prog='dot', root=0)
plt.title("Some title")
nx.draw_networkx_nodes(G, pos, node_color=color_vector, node_shape='s', node_size=500)
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos, font_size=10, font_color="white")
plt.show()

And this is what I get... enter image description here

I would greatly appreciate, if someone could point me towards the right direction. Thank you so much!!!

EDIT1 Thanks to a comment I now have arrows between all correct nodes. It turns out the nodes were too large and overlapping. Now it looks like this: enter image description here.

I would stil like to get it horizontal and somehow scale the arrow length, if anyone knows...

EDIT2 I managed to get it working properly now. I reduced the arrow length by sequeezing the plot via figure size (not ideal solution, but gets the job done...) The horizontal flip I managed to get working after figuring out that there was a conflict between root and the extra arguments passed in the graphviz_lazout function. I used this documentation to get there. See code below:

def blocktree_plot(model):
    honest_blocks = []
    selfish_blocks = []
    
    for block in model.block_tree.tree.nodes():
        if model.block_tree[block]["miner_is_selfish"] == True:
            selfish_blocks.append(model.block_tree[block]["id"])
        else:
            honest_blocks.append(model.block_tree[block]["id"])

    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(6, 2), sharex=True, sharey=True)
    G = model.block_tree.tree
    H = G.reverse(copy=True)
    pos = graphviz_layout(H, prog='dot', args='-Grankdir="RL"')

    plt.title(r"Blockchain with Selfish Mining ($\alpha$ = {})".format(alpha))

    nx.draw_networkx_nodes(H,pos=pos, nodelist=honest_blocks, node_color='green', label="Honest miner", node_shape='s', node_size=200)
    nx.draw_networkx_nodes(H,pos=pos, nodelist=selfish_blocks, node_color='red', label="Selfish miner", node_shape='s', node_size=200)
    nx.draw_networkx_nodes(H,pos=pos, nodelist=[0], node_color='blue', label="Genesis block", node_shape='s', node_size=200)    

    nx.draw_networkx_edges(H, pos, arrows=True)
    nx.draw_networkx_labels(H, pos, font_size=10, font_color="white")
    # plt.legend(labelspacing=0.8, fontsize=9, frameon=False, borderpad=0.1)
    plt.show()

And this is what it looks like now: enter image description here

Upvotes: 3

Views: 1781

Answers (1)

Joel
Joel

Reputation: 23827

I don't know if it's possible to easily scale the edge lengths, so I'm leaving that part unanswered, and hoping someone else has a suggestion.

If you basically want to just rotate your figure, what you can do is the following:

tmppos = graphviz_layout(G, prog='dot', root=0)
pos = {node: (-y, x) for node, x,y in tmppos.items()}

which should take the original x and y coordinates and flip them (and make the downward direction in original turn into a rightward shift horizontally in the new).

Upvotes: 2

Related Questions