summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKelly Boothby <boothby@dwavesys.com>2020-01-20 11:37:15 -0800
committerDan Schult <dschult@colgate.edu>2020-01-20 14:37:15 -0500
commit15e17c0a2072ea56df3d9cd9152ee682203e8cd9 (patch)
tree055c0287de8bcd64d2c65687674a4c39cce52195
parente2e147bbd5ed76acbb926e7cfb2932347fb80833 (diff)
downloadnetworkx-15e17c0a2072ea56df3d9cd9152ee682203e8cd9.tar.gz
fix initializer for kamada_kawai_layout (networkx #3658) (#3782)
* fixed high-dimensional initializer for kamada_kawai_layout (networkx #3658) * added tests for kamada_kawai 3d * increased test coverage of kamada_kawai_layout * fixed empty-graph oversight in kamada_kawai_layout * removed unused variable vpos from smoke tests Fixes #3658
-rw-r--r--networkx/drawing/layout.py6
-rw-r--r--networkx/drawing/tests/test_layout.py116
2 files changed, 76 insertions, 46 deletions
diff --git a/networkx/drawing/layout.py b/networkx/drawing/layout.py
index 9a41701c..b7779d08 100644
--- a/networkx/drawing/layout.py
+++ b/networkx/drawing/layout.py
@@ -687,6 +687,8 @@ def kamada_kawai_layout(G, dist=None,
G, center = _process_params(G, center, dim)
nNodes = len(G)
+ if nNodes == 0:
+ return {}
if dist is None:
dist = dict(nx.shortest_path_length(G, weight=weight))
@@ -701,7 +703,9 @@ def kamada_kawai_layout(G, dist=None,
dist_mtx[row][col] = rdist[nc]
if pos is None:
- if dim >= 2:
+ if dim >= 3:
+ pos = random_layout(G, dim=dim)
+ elif dim == 2:
pos = circular_layout(G, dim=dim)
else:
pos = {n: pt for n, pt in zip(G, np.linspace(0, 1, len(G)))}
diff --git a/networkx/drawing/tests/test_layout.py b/networkx/drawing/tests/test_layout.py
index 1a8dc17e..17e06d75 100644
--- a/networkx/drawing/tests/test_layout.py
+++ b/networkx/drawing/tests/test_layout.py
@@ -48,46 +48,48 @@ class TestLayout:
def test_smoke_empty_graph(self):
G = []
- vpos = nx.random_layout(G)
- vpos = nx.circular_layout(G)
- vpos = nx.planar_layout(G)
- vpos = nx.spring_layout(G)
- vpos = nx.fruchterman_reingold_layout(G)
- vpos = nx.spectral_layout(G)
- vpos = nx.shell_layout(G)
- vpos = nx.bipartite_layout(G, G)
- vpos = nx.spiral_layout(G)
- # FIXME vpos = nx.kamada_kawai_layout(G)
+ nx.random_layout(G)
+ nx.circular_layout(G)
+ nx.planar_layout(G)
+ nx.spring_layout(G)
+ nx.fruchterman_reingold_layout(G)
+ nx.spectral_layout(G)
+ nx.shell_layout(G)
+ nx.bipartite_layout(G, G)
+ nx.spiral_layout(G)
+ nx.kamada_kawai_layout(G)
def test_smoke_int(self):
G = self.Gi
- vpos = nx.random_layout(G)
- vpos = nx.circular_layout(G)
- vpos = nx.planar_layout(G)
- vpos = nx.spring_layout(G)
- vpos = nx.fruchterman_reingold_layout(G)
- vpos = nx.fruchterman_reingold_layout(self.bigG)
- vpos = nx.spectral_layout(G)
- vpos = nx.spectral_layout(G.to_directed())
- vpos = nx.spectral_layout(self.bigG)
- vpos = nx.spectral_layout(self.bigG.to_directed())
- vpos = nx.shell_layout(G)
- vpos = nx.spiral_layout(G)
- vpos = nx.kamada_kawai_layout(G)
- vpos = nx.kamada_kawai_layout(G, dim=1)
+ nx.random_layout(G)
+ nx.circular_layout(G)
+ nx.planar_layout(G)
+ nx.spring_layout(G)
+ nx.fruchterman_reingold_layout(G)
+ nx.fruchterman_reingold_layout(self.bigG)
+ nx.spectral_layout(G)
+ nx.spectral_layout(G.to_directed())
+ nx.spectral_layout(self.bigG)
+ nx.spectral_layout(self.bigG.to_directed())
+ nx.shell_layout(G)
+ nx.spiral_layout(G)
+ nx.kamada_kawai_layout(G)
+ nx.kamada_kawai_layout(G, dim=1)
+ nx.kamada_kawai_layout(G, dim=3)
def test_smoke_string(self):
G = self.Gs
- vpos = nx.random_layout(G)
- vpos = nx.circular_layout(G)
- vpos = nx.planar_layout(G)
- vpos = nx.spring_layout(G)
- vpos = nx.fruchterman_reingold_layout(G)
- vpos = nx.spectral_layout(G)
- vpos = nx.shell_layout(G)
- vpos = nx.spiral_layout(G)
- vpos = nx.kamada_kawai_layout(G)
- vpos = nx.kamada_kawai_layout(G, dim=1)
+ nx.random_layout(G)
+ nx.circular_layout(G)
+ nx.planar_layout(G)
+ nx.spring_layout(G)
+ nx.fruchterman_reingold_layout(G)
+ nx.spectral_layout(G)
+ nx.shell_layout(G)
+ nx.spiral_layout(G)
+ nx.kamada_kawai_layout(G)
+ nx.kamada_kawai_layout(G, dim=1)
+ nx.kamada_kawai_layout(G, dim=3)
def check_scale_and_center(self, pos, scale, center):
center = numpy.array(center)
@@ -113,6 +115,10 @@ class TestLayout:
sc(nx.spiral_layout(G, scale=2, center=c), scale=2, center=c)
sc(nx.kamada_kawai_layout(G, scale=2, center=c), scale=2, center=c)
+ c = (2, 3, 5)
+ sc(nx.kamada_kawai_layout(G, dim=3, scale=2, center=c), scale=2, center=c)
+
+
def test_planar_layout_non_planar_input(self):
G = nx.complete_graph(9)
pytest.raises(nx.NetworkXException, nx.planar_layout, G)
@@ -135,6 +141,10 @@ class TestLayout:
sc(nx.spiral_layout(G), scale=1, center=c)
sc(nx.kamada_kawai_layout(G), scale=1, center=c)
+ c = (0, 0, 0)
+ sc(nx.kamada_kawai_layout(G, dim=3), scale=1, center=c)
+
+
def test_circular_planar_and_shell_dim_error(self):
G = nx.path_graph(4)
pytest.raises(ValueError, nx.circular_layout, G, dim=1)
@@ -190,7 +200,7 @@ class TestLayout:
def test_center_parameter(self):
G = nx.path_graph(1)
- vpos = nx.random_layout(G, center=(1, 1))
+ nx.random_layout(G, center=(1, 1))
vpos = nx.circular_layout(G, center=(1, 1))
assert tuple(vpos[0]) == (1, 1)
vpos = nx.planar_layout(G, center=(1, 1))
@@ -218,6 +228,7 @@ class TestLayout:
pytest.raises(ValueError, nx.spectral_layout, G, dim=3, center=(1, 1))
pytest.raises(ValueError, nx.shell_layout, G, center=(1, 1, 1))
pytest.raises(ValueError, nx.spiral_layout, G, center=(1, 1, 1))
+ pytest.raises(ValueError, nx.kamada_kawai_layout, G, center=(1, 1, 1))
def test_empty_graph(self):
G = nx.empty_graph()
@@ -239,6 +250,8 @@ class TestLayout:
assert vpos == {}
vpos = nx.spiral_layout(G, center=(1, 1))
assert vpos == {}
+ vpos = nx.kamada_kawai_layout(G, center=(1, 1))
+ assert vpos == {}
def test_bipartite_layout(self):
G = nx.complete_bipartite_graph(3, 5)
@@ -282,19 +295,11 @@ class TestLayout:
assert almost_equal(grad[0], -0.5)
assert almost_equal(grad[1], 0.5)
- def test_kamada_kawai_costfn_2d(self):
+ def check_kamada_kawai_costfn(self, pos, invdist, meanwt, dim):
costfn = nx.drawing.layout._kamada_kawai_costfn
- pos = numpy.array([[1.3, -3.2],
- [2.7, -0.3],
- [5.1, 2.5]])
- invdist = 1 / numpy.array([[0.1, 2.1, 1.7],
- [2.1, 0.2, 0.6],
- [1.7, 0.6, 0.3]])
- meanwt = 0.3
-
cost, grad = costfn(pos.ravel(), numpy, invdist,
- meanweight=meanwt, dim=2)
+ meanweight=meanwt, dim=dim)
expected_cost = 0.5 * meanwt * numpy.sum(numpy.sum(pos, axis=0) ** 2)
for i in range(pos.shape[0]):
@@ -321,6 +326,27 @@ class TestLayout:
assert almost_equal(grad[idx], (cplus - cminus) / (2 * dx),
places=5)
+ def test_kamada_kawai_costfn(self):
+ invdist = 1 / numpy.array([[0.1, 2.1, 1.7],
+ [2.1, 0.2, 0.6],
+ [1.7, 0.6, 0.3]])
+ meanwt = 0.3
+
+ # 2d
+ pos = numpy.array([[1.3, -3.2],
+ [2.7, -0.3],
+ [5.1, 2.5]])
+
+ self.check_kamada_kawai_costfn(pos, invdist, meanwt, 2)
+
+ # 3d
+ pos = numpy.array([[0.9, 8.6, -8.7],
+ [-10, -0.5, -7.1],
+ [9.1, -8.1, 1.6]])
+
+ self.check_kamada_kawai_costfn(pos, invdist, meanwt, 3)
+
+
def test_spiral_layout(self):
G = self.Gs