I am generating simple syntactic dependecies trees such as in the following example:
Best layout is "dot" but on the top row things get very crowded. Is there any parameter or other way to avoid node labels overlapping with neighbouring nodes (and ideally edges)?
Maybe some matplotlib parameter to "draw on a very wide canvas"? (sorry totally matplotlib ignorant).
Here is the code I am currently using:
import platform
import matplotlib
import matplotlib.pyplot as plt
import stanza
import networkx as nx
from netgraph import InteractiveGraph
if platform.system() == "Darwin":
matplotlib.use("TkAgg") # MacOSX backend is bugged; use TkAgg
def display_graph(G: nx.DiGraph, title: str):
"""Use netgraph to show the graph"""
nodecolors = nx.get_node_attributes(G, "nodecol")
nodelabels = nx.get_node_attributes(G, "lemma")
nodeshapes = nx.get_node_attributes(G, "nodeshape")
edgelabels = nx.get_edge_attributes(G, "label")
# now plot the graph
plot_instance = InteractiveGraph(
G,
node_layout="dot",
node_labels=nodelabels,
node_color=nodecolors,
node_label_fontdict=dict(size=12),
node_shape=nodeshapes,
node_alpha=0.5, # node transparency
edge_labels=edgelabels,
edge_layout="curved",
arrows=True,
)
plt.suptitle(title, wrap=True)
plt.show()
return
CodePudding user response:
Is there any parameter or other way to avoid node labels overlapping with neighbouring nodes (and ideally edges)?
If you set the parameter node_label_offset
to some float, e.g. node_label_offset=0.05
, then netgraph will find the position 0.05 away from the node center that is furthest away from all other nodes and edges. However, there is no guarantee that there aren't any label overlaps as the space may simply be too crowded.
Maybe some matplotlib parameter to "draw on a very wide canvas"? (sorry totally matplotlib ignorant).
The width and height of the canvas are controlled by the shape
parameter. The default is shape=(1, 1)
. So shape=(2, 2)
would double the size of the canvas.
However, as fontsizes in matplotlib (and hence netgraph) are defined in display units, you would also have to increase the size of the matplotlib figure to decrease the size of the text relative to the whole figure.
fig, ax = plt.subplots(figsize=(2*6.4, 2*4.8)) # default is 6.4, 4.8
plot_instance = InteractiveGraph(G, node_layout='dot', shape=(2, 2), ax=ax, ...)
Further suggestions:
- Remove the node edges.
node_edge_color=nodecolors
ornode_edge_width=0.
. - I would set the node alpha to one, as otherwise the underlying edge becomes visible. Use lighter node colors if needed.
Basically, you want to remove any source of contrast that distract from the text if you want the labels to "pop".