Since the maximum length of a vertex can be sqrt(2), we can
assume that our graph needs to live in grid world, where
nodes have positive integer x and y coordinates, and vertices
can only connect nearby nodes, subject to the length restriction.
The solution would be to extend components one at a time with
nodes and vertices that bring the components closer together.
The connected graph for the question would add nodes 9 and 10,
with connecting vertices. See first picture below.

Besides the test mentioned in the OP's question,
it seems that the more interesting test would be with node 4 in position (3, 4). The optimal solution in this case in one Steiner point (see enter link description here).
To build such a solution for small graphs, we can use an
algorithm that adds one node and edge connecting one node of
the pair of nodes that is closest to each other. To accommodate
building a Steiner tree, we allow for choosing the location of
point in a diagonal location. That is, node 2 and 6 have the
same y coordinate, but we'll create node 9 diagonally, so that
we can build a bridge to the next closest neighbor. See picture
below.

To prevent building extra nodes, nodes should be added in
turns. Since we have numbered the nodes, this can be done by
selecting the smallest node number to grow from. This leads
to growing a bigger Steiner tree when more space needs to
be crossed. See picture below, where nodes 9 through 12
where added to the original graph.

The rough algorithm for this (and wildly inefficient) is as
follows. The Euclidean distance function is modified from
Russell & Norvig (Github library with Artificial Intelligence,
A Modern Approach by Stuart Russell and Peter Norvig).
import itertools
import networkx as nx
import numpy as np
# Assumes graph G created same or similar to code in OP's question
def closest_nodes(c1, c2, components):
nodes_c1 = [(n, G.nodes[n]['pos']) for n in components[c1]]
nodes_c2 = [(n,G.nodes[n]['pos']) for n in components[c2]]
xnodes = itertools.product(nodes_c1, nodes_c2)
closest = min(xnodes, key=lambda x: euclidean_distance(x[0], x[1]))
return euclidean_distance(closest[0], closest[1]), closest
def next_closest_node(n1, c1, c2, components):
other_nodes = []
for i,v in enumerate(components):
if i == c1 or i == c2:
continue
other_nodes.extend((n, G.nodes[n]['pos']) for n in v)
if len(other_nodes) == 0:
return None
# print('next closest', n1, other_nodes)
closest = min(other_nodes, key=lambda x: euclidean_distance(x, n1))
return closest
def closest_comps(components):
xcomps = itertools.combinations(range(len(components)), 2)
closest = min(xcomps,
key=lambda x: closest_nodes(x[0], x[1], components)[0])
return closest
def euclidean_distance(x, y):
xc = x[1]
yc = y[1]
# print('e_d', x, y)
return np.sqrt(sum((_x - _y) ** 2 for _x, _y in zip(xc, yc)))
def determine_pos(sel_comps, sel_nodes, components):
next_closest = next_closest_node(sel_nodes[1][0], *sel_comps, components)
# Grow from the smallest node number
if sel_nodes[1][0][0] < sel_nodes[1][1][0]:
from_node = sel_nodes[1][0][0]
start_pos = sel_nodes[1][0][1]
target_pos = sel_nodes[1][1][1]
else:
from_node = sel_nodes[1][1][0]
start_pos = sel_nodes[1][1][1]
target_pos = sel_nodes[1][0][1]
diff_x = target_pos[0]-start_pos[0]
diff_y = target_pos[1]-start_pos[1]
new_x, new_y = start_pos[0], start_pos[1]
if diff_x != 0:
new_x += diff_x//abs(diff_x)
elif next_closest is not None:
diff_x = next_closest[1][0]-start_pos[0]
if diff_x != 0:
new_x += diff_x//abs(diff_x)
if diff_y != 0:
new_y += diff_y//abs(diff_y)
elif next_closest is not None:
diff_y = next_closest[1][1]-start_pos[1]
if diff_y != 0:
new_y += diff_y//abs(diff_y)
return from_node, (new_x, new_y)
while not nx.is_connected(G):
components = [c for c in
sorted(nx.connected_components(G), key=len, reverse=True)]
sel_comps = closest_comps(components)
sel_nodes = closest_nodes(*sel_comps, components)
sel_dist = euclidean_distance(sel_nodes[1][0], sel_nodes[1][1])
edge_needed = sel_dist <= np.sqrt(2)
if edge_needed:
G.add_edge(sel_nodes[1][0][0], sel_nodes[1][1][0])
else:
new_pos = determine_pos(sel_comps, sel_nodes, components)
new_node = G.number_of_nodes() + 1
G.add_node(new_node, pos=new_pos[1])
G.add_edge(new_pos[0], new_node)
pos = nx.get_node_attributes(G, 'pos')
nx.draw(G, pos, with_labels=True)