PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, June 27, 2022

[FIXED] How can I define the size of the graph and draw arced edges with a certain color in networkx?

 June 27, 2022     graph, networkx, python     No comments   

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)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing