Issue
I am having trouble trying to figure out how to define the size of the output file when drawing the graph in networkx and also displaying cycles between nodes.
Problem definition
I have a list of nodes which **may**, or **may not**, have cycles between them. As you can see down below in the code I provide, I am using two colors to distinguish two different kinds of edges (the color of the edge determines this difference).Current situation
So far I have not been able to display different colors on the edges (according to the documentation colors can be defined when adding the edges), neither have I been able to avoid edge overlaping (when two nodes compone a cycle one edge overlaps the other so only one is visible).
I also have not been able to set the size of the figure when drawing (or saving the plot mith matplotlib). I have seen some questions that ask about the size of the output but none have worked for me so far (a few examples are commented in the code, but I have tried some others).
def plot(self):
"""
plot graph
"""
nx.draw(self.G, with_labels = True)
#nx.draw_kamada_kawai(self.G, with_labels = True)
#plt.figure(1, figsize=(200, 80), dpi=60, font_weight='normal')
#plt.figure(figsize=(280,80))
plt.savefig("filename.png")
Current Output
[![current output][2]][2]Desired Output
I need the same output but with **arced edges**, drawn with the **provided color**, so they won't **overlap one another**. I also need the final output size to adapt to the size of the graph. As you can see in the image the name of the **nodes are cutoff and the graph is clearly croped**. If you try to change the value of number_of_nodes you will see that everything is cutoff... Keep in mind that these graphs could have from 25 to 100 nodes with multiple edges between them (including the cycles)My code so far
from tkinter.ttk import Notebook
import networkx as nx
import matplotlib.pyplot as plt
class Graph:
"""
create and visualize a graph using networkx
"""
def __init__(self):
"""
basic constructor
"""
self.G = nx.MultiDiGraph()
def addNodes(self,nodes, options = {'color' : 'blue'}):
"""
add nodes to the graph
"""
#asserts
assert(self.G is None, 'graph not created')
assert(options is None, 'options parameter is none type')
assert(not isinstance(nodes, list), 'nodes parameter must be a list')
#add nodes with options
for n in nodes:
opt = options
opt['label'] = n
self.G.add_nodes_from(
[(n, opt)]
)
def addEdges(self, edges, options = {'color' : 'green'}):
"""
add edges to the graph
"""
#asserts
assert(self.G is None, 'graph not created')
assert(options is None, 'options parameter is none type')
assert(not isinstance(edges, list), 'edges parameter must be a list')
#add edges with options
for n in edges:
opt = options
opt['label'] = n
self.G.add_edges_from(
[n + (options,)]
)
print([n + (options,)])
#self.G.add_edges_from(edges, options)
def removeNodes(self, nodes):
"""
remove nodes from graph
"""
assert(self.G is None, 'graph not created')
assert(not isinstance(nodes, list), 'nodes parameter must be a list')
self.G.remove_nodes_from(nodes)
def removeEdges(self,edges):
"""
remove edges from graph
"""
assert(self.G is None, 'graph not created')
assert(not isinstance(edges, list), 'edges parameter must be a list')
self.G.remove_edges_from(edges)
def plot(self):
"""
plot graph
"""
nx.draw(self.G, with_labels = True)
#nx.draw_kamada_kawai(self.G, with_labels = True)
#plt.figure(1, figsize=(200, 80), dpi=60, font_weight='normal')
#plt.figure(figsize=(280,80))
plt.savefig("filename.png")
def save_graph(self, filename):
"""
save graph to file
"""
pass
class CubeGraph(Graph):
"""
this class handles graphs for cubes
"""
def __init__(self, nodes, green_edges, red_edges):
"""
constructor for cube graph
"""
#asserts
assert(not isinstance(nodes, list), 'nodes parameter must be a list')
assert(not isinstance(green_edges, list), 'green_edges parameter must be a list')
assert(not isinstance(red_edges, list), 'red_edges parameter must be a list')
#assign variables
self._nodes = nodes
self._greenEdges = green_edges
self._redEdges = red_edges
#init parent object
super().__init__()
def createAll(self):
"""
create the graph with all the nodes and edges
"""
self.addNodes(self._nodes)
self.addEdges(self._greenEdges, {'color' : 'green'})
self.addEdges(self._redEdges, {'color' : 'red'})
def create(self, node):
"""
create a graph only with related node
"""
assert(node in self._nodes, 'node parameter is not nodes list provided at initialization')
#clean the graph
self.removeEdges(self._redEdges)
self.removeEdges(self._greenEdges)
self.removeNodes(self._nodes)
#make sure node is lower case
node = node.lower()
#filter only those edges matching the node
green_filtered = list(filter(lambda x : x[0] == node, self._greenEdges))
red_filtered = list(filter(lambda x : x[1] == node, self._redEdges))
#add nodes and edges to graph
self.addNodes(node)
self.addEdges(green_filtered, {'color' : 'green'})
self.addEdges(red_filtered, {'color' : 'red'})
number_of_nodes = 6
nodes = ['0000 very long and unique string number {}'.format(i) for i in range(0,number_of_nodes)]
green = []
red = []
green.append(('0000 very long and unique string number 0', '0000 very long and unique string number 1'))
red.append(('0000 very long and unique string number 1', '0000 very long and unique string number 0'))
green.append(('0000 very long and unique string number 2', '0000 very long and unique string number 3'))
red.append(('0000 very long and unique string number 3', '0000 very long and unique string number 2'))
green.append(('0000 very long and unique string number 4', '0000 very long and unique string number 5'))
red.append(('0000 very long and unique string number 5', '0000 very long and unique string number 4'))
net = CubeGraph(nodes, green, red)
net.createAll()
net.plot()
print('')
Solution
After strugling a lot with the formating of the edges I got what I needed. The draw function from nx wasa not the draw option that I needed after all, because, in order to achieve what I wanted, I needed to create a layout so the position of the nodes could be calculated. After that the functions draw_networkx_nodes and draw_networkx_edges provided the utility I was looking for. The function looks like this:
def plot(self):
"""
plot graph
"""
fig = plt.figure(1, figsize=(self.IMAGE_WIDTH, self.IMAGE_HEIGHT), dpi=60)
# Compute position of nodes
pos = nx.kamada_kawai_layout(self.G)
# Draw nodes and edges
nx.draw_networkx_nodes(self.G, pos, labels = list(self.G.nodes))
nx.draw_networkx_labels(self.G, pos, {n: n for n in list(self.G.nodes)}, font_size=10)
nx.draw_networkx_edges(
self.G, pos,
connectionstyle="arc3,rad=0.1"
,edge_color = self.edgesColor
,arrowsize=20
)
#nx.draw_networkx_edge_labels(self.G, pos, {n: n for n in list(self.G.edges)}, font_size=6)
plt.show()
Answered By - M. Villanueva Answer Checked By - Willingham (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.