Since the other answers require the user to adjust some parameter manually in an iterative process, I wanted to add my own answer. It is automatic, but the current implementation only works if all node sizes are equal.
Node sizes are in points, therefore they don't scale with the image. Although this answer works programmatically, it doesn't work if you interactively change the window size of the figure. The first half of the fix_graph_scale
function calculates the node radius in terms of the future x and y scale. The second half sets the axis scales such that they include all node positions plus half of the node size.
The get_ax_size
function is from unutbu's answer with slight modifications.
import matplotlib.pyplot as plt
import networkx as nx
def get_ax_size(ax):
bbox = ax.get_window_extent().transformed(ax.figure.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
width *= 72
height *= 72
return width, height
def fix_graph_scale(ax,pos,node_size = 300):
node_radius = (node_size / 3.14159265359)**0.5
min_x = min(i_pos[0] for i_pos in pos.values())
max_x = max(i_pos[0] for i_pos in pos.values())
min_y = min(i_pos[1] for i_pos in pos.values())
max_y = max(i_pos[1] for i_pos in pos.values())
ax_size_x, ax_size_y = get_ax_size(ax)
points_to_x_axis = (max_x - min_x)/(ax_size_x-node_radius*2)
points_to_y_axis = (max_y - min_y)/(ax_size_y-node_radius*2)
node_radius_in_x_axis = node_radius * points_to_x_axis
node_radius_in_y_axis = node_radius * points_to_y_axis
ax_min_x = min_x - node_radius_in_x_axis
ax_max_x = max_x + node_radius_in_x_axis
ax_min_y = min_y - node_radius_in_y_axis
ax_max_y = max_y + node_radius_in_y_axis
ax.set_xlim([ax_min_x, ax_max_x])
ax.set_ylim([ax_min_y, ax_max_y])
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.scatter(range(10), range(10))
G = nx.erdos_renyi_graph(20, p=0.1)
pos = nx.drawing.spring_layout(G)
nx.draw_networkx(G,pos,ax=ax2)
default_node_size = 300
fix_graph_scale(ax2,pos,node_size = default_node_size)
plt.show()
Sample result