paulbrodersen / netgraph

Publication-quality network visualisations in python
GNU General Public License v3.0
660 stars 39 forks source link

Curved layout does not work for multi-component graphs. #48

Closed lcastri closed 1 year ago

lcastri commented 2 years ago

Hi Paul,

I am having a problem with the scale parameter of the Graph class. First of all, I am not assigning any value to it and I leave it as the default (1.0 1.0). Debugging a bit, I figure out that that value is changed internally by the function "get_layout_for_multiple_components" to (0.67, 1). In this way I always get an error saying that some of the nodes are outside the origin-scale area.

I tried with the spring, circular and multipartite layout and all of them produce the same error. Am I setting something wrong?

Graph(G, 
            node_layout = 'circular',
            node_size = 8,
            node_color = node_color,
            node_labels = node_label,
            node_edge_width = border,
            node_label_fontdict = dict(size=font_size),
            node_edge_color = edge_color,
            node_label_offset = 0.15,
            node_alpha = 1,

            arrows = True,
            edge_layout = 'curved',
            edge_label = show_edge_labels,
            edge_labels = edge_label,
            edge_label_fontdict = dict(size=font_size),
            edge_color = edge_color, 
            edge_width = edge_width,
            edge_label_position = 0.35)
paulbrodersen commented 2 years ago

Nope, looks all fine to me. Can you provide me with the edge list of you graph? Then I will take a look once I am back from my holiday (if I can fit it in, then earlier but I won't make any promises).

lcastri commented 2 years ago

Hi Paul,

sorry for the late reply. I tried to replicate the error in order to be more precise as possible. I am using the 'dot' node layout as follows:

Graph(G, 
                node_layout = 'dot',
                node_size = 8,
                node_color = node_color,
                node_labels = node_label,
                node_edge_width = border,
                node_label_fontdict = dict(size=font_size),
                node_edge_color = edge_color,
                node_label_offset = 0.15,
                node_alpha = 1,

                arrows = True,
                edge_layout = 'curved',
                edge_label = show_edge_labels,
                edge_labels = edge_label,
                edge_label_fontdict = dict(size=font_size),
                edge_color = edge_color, 
                edge_width = edge_width,
                edge_alpha = 1,
                edge_label_position = 0.35)

with the following nodes and edges:

nodes = ['$X_0$', '$X_1$', '$X_2$', '$X_3$', '$X_4$', '$X_5$', '$X_6$']
edges = [('$X_4$', '$X_0$'), ('$X_1$', '$X_2$'), ('$X_5$', '$X_4$'), ('$X_6$', '$X_4$'), ('$X_6$', '$X_5$')]

and I obtain this error:

Some given node positions are not within the data range specified by `origin` and `scale`!
    Origin : 0.0, 0.0
    Scale  : 0.7076071167363686, 1.0
The following nodes do not fall within this range:
    $X_3$ : (0.7462532271425445, 0.7752108975790752)
This error can occur if the graph contains multiple components but some or all node positions are initialised explicitly (i.e. node_positions != None).

I get this error even if I try to set the scale value but I noticed that it appears only if I use the edge_layout = 'curved'.

Thanks

paulbrodersen commented 1 year ago

Hi Luca, so I figured out that the issue occurs when two conditions are met:

  1. The network has multiple components (in your case there are 3).
  2. The edge layout is curved.

I have a deadline tomorrow, so I can't work on the problem any more today but I will try to fix the issue on Thursday or Friday.

paulbrodersen commented 1 year ago

Alright, I think I now fixed the last remaining problems. Using my (simplified) version of your code, the graph now looks like this:

import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph

nodes = ['$X_0$', '$X_1$', '$X_2$', '$X_3$', '$X_4$', '$X_5$', '$X_6$']
edges = [('$X_4$', '$X_0$'), ('$X_1$', '$X_2$'), ('$X_5$', '$X_4$'), ('$X_6$', '$X_4$'), ('$X_6$', '$X_5$')]

G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)

Graph(G,
      node_layout='dot',
      edge_layout='curved',
      node_labels=True,
      node_label_offset=0.075,
      node_label_fontdict=dict(size=20),
      origin=(0, 0),
      scale=(1, 1),
)

plt.show()

Figure_1

Thanks for raising the issue. It helped me uncover a surprising amount of problems that arose from interactions between the dot layout and the fact that you have multiple components.