or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis.mdclustering.mdcommunity.mddata-types.mdgraph-creation.mdgraph-structure.mdindex.mdio-formats.mdlayout.mdsequences.mdvisualization.md

layout.mddocs/

0

# Layout

1

2

Graph layout and positioning algorithms for visualization and spatial analysis. igraph provides over 30 layout algorithms ranging from force-directed methods to specialized algorithms for trees, hierarchies, and large networks.

3

4

## Capabilities

5

6

### Force-Directed Layouts

7

8

Physics-based layouts that simulate forces between vertices to achieve aesthetically pleasing arrangements.

9

10

```python { .api }

11

class Graph:

12

def layout_fruchterman_reingold(self, weights=None, maxiter=500, area=None, coolexp=1.5, repulserad=None, dim=2, **kwargs):

13

"""

14

Fruchterman-Reingold force-directed layout.

15

16

Parameters:

17

- weights: str/list, edge weights (shorter for higher weights)

18

- maxiter: int, maximum iterations

19

- area: float, area of layout (None for automatic)

20

- coolexp: float, cooling exponent

21

- repulserad: float, repulsion radius (None for automatic)

22

- dim: int, number of dimensions (2 or 3)

23

24

Returns:

25

Layout object with vertex coordinates

26

"""

27

28

def layout_kamada_kawai(self, weights=None, maxiter=None, epsilon=0, kkconst=None, dim=2, **kwargs):

29

"""

30

Kamada-Kawai spring-based layout.

31

32

Parameters:

33

- weights: edge weights

34

- maxiter: int, maximum iterations (None for automatic)

35

- epsilon: float, stopping criterion

36

- kkconst: float, spring constant (None for automatic)

37

- dim: int, dimensions

38

39

Returns:

40

Layout object

41

"""

42

43

def layout_spring(self, weights=None, maxiter=500, area=None, coolexp=1.5, repulserad=None, dim=2, **kwargs):

44

"""

45

Alias for layout_fruchterman_reingold().

46

"""

47

48

def layout_davidson_harel(self, weights=None, maxiter=10, fineiter=None, cool_fact=0.75, weight_node_dist=1.0, weight_border=0.0, weight_edge_lengths=None, weight_edge_crossings=1.0, weight_node_edge_dist=0.2, **kwargs):

49

"""

50

Davidson-Harel layout with multiple aesthetic criteria.

51

52

Parameters:

53

- weights: edge weights

54

- maxiter: int, coarse iterations

55

- fineiter: int, fine-tuning iterations

56

- cool_fact: float, cooling factor

57

- weight_*: float, weights for different aesthetic criteria

58

59

Returns:

60

Layout object

61

"""

62

```

63

64

**Usage Examples:**

65

66

```python

67

import igraph as ig

68

69

# Create sample graph

70

g = ig.Graph.Barabasi(50, m=2)

71

72

# Fruchterman-Reingold (most common)

73

fr_layout = g.layout_fruchterman_reingold()

74

print(f"FR layout shape: {len(fr_layout)} x {len(fr_layout[0])}")

75

76

# With edge weights (closer vertices for higher weights)

77

g.es["weight"] = [1.0 + i*0.1 for i in range(g.ecount())]

78

weighted_fr = g.layout_fruchterman_reingold(weights="weight")

79

80

# Kamada-Kawai (good for smaller graphs)

81

kk_layout = g.layout_kamada_kawai(maxiter=1000)

82

83

# 3D layout

84

fr_3d = g.layout_fruchterman_reingold(dim=3)

85

print(f"3D layout shape: {len(fr_3d)} x {len(fr_3d[0])}") # N x 3

86

87

# Davidson-Harel with custom weights

88

dh_layout = g.layout_davidson_harel(

89

maxiter=20,

90

weight_node_dist=2.0,

91

weight_edge_crossings=0.5

92

)

93

```

94

95

### Tree and Hierarchical Layouts

96

97

Specialized layouts for trees, DAGs, and hierarchical structures.

98

99

```python { .api }

100

class Graph:

101

def layout_reingold_tilford(self, mode=ALL, root=None):

102

"""

103

Reingold-Tilford tree layout.

104

105

Parameters:

106

- mode: tree direction (ALL, OUT, IN)

107

- root: int/list, root vertices (None for automatic)

108

109

Returns:

110

Layout object with hierarchical positioning

111

"""

112

113

def layout_reingold_tilford_circular(self, mode=ALL, root=None):

114

"""

115

Circular Reingold-Tilford layout.

116

117

Parameters:

118

- mode: tree direction

119

- root: root vertices

120

121

Returns:

122

Layout object in circular arrangement

123

"""

124

125

def layout_sugiyama(self, layers=None, weights=None, hgap=1, vgap=1, maxiter=100, **kwargs):

126

"""

127

Sugiyama layered layout for directed acyclic graphs.

128

129

Parameters:

130

- layers: list, predefined layer assignment

131

- weights: edge weights

132

- hgap: float, horizontal gap between vertices

133

- vgap: float, vertical gap between layers

134

- maxiter: int, maximum iterations for crossing reduction

135

136

Returns:

137

Layout object with layered structure

138

"""

139

```

140

141

**Usage Examples:**

142

143

```python

144

# Tree layouts

145

tree = ig.Graph.Tree(31, children=2) # Binary tree

146

147

# Standard tree layout

148

tree_layout = tree.layout_reingold_tilford(root=[0])

149

150

# Circular tree layout

151

circular_tree = tree.layout_reingold_tilford_circular(root=[0])

152

153

# For directed acyclic graphs

154

dag = ig.Graph([(0,1), (0,2), (1,3), (1,4), (2,4), (2,5), (3,6), (4,6), (5,6)], directed=True)

155

156

# Sugiyama layered layout

157

sugiyama_layout = dag.layout_sugiyama()

158

159

# Manual layer assignment

160

layers = [0, 1, 1, 2, 2, 2, 3] # Layer for each vertex

161

manual_sugiyama = dag.layout_sugiyama(layers=layers, hgap=2, vgap=1.5)

162

```

163

164

### Large Graph Layouts

165

166

Efficient algorithms designed for large networks with thousands or millions of vertices.

167

168

```python { .api }

169

class Graph:

170

def layout_drl(self, weights=None, dim=2, fixednode=None, **kwargs):

171

"""

172

DrL (Distributed Recursive Layout) for large graphs.

173

174

Parameters:

175

- weights: edge weights

176

- dim: int, dimensions (2 or 3)

177

- fixednode: list, vertices with fixed positions

178

179

Returns:

180

Layout object

181

"""

182

183

def layout_graphopt(self, weights=None, niter=500, node_charge=0.001, node_mass=30, spring_length=0, spring_constant=1, max_sa_movement=5, **kwargs):

184

"""

185

GraphOpt layout algorithm.

186

187

Parameters:

188

- weights: edge weights

189

- niter: int, number of iterations

190

- node_charge: float, vertex charge (repulsion)

191

- node_mass: float, vertex mass

192

- spring_length: float, natural spring length

193

- spring_constant: float, spring force constant

194

- max_sa_movement: float, maximum movement per iteration

195

196

Returns:

197

Layout object

198

"""

199

200

def layout_lgl(self, weights=None, maxiter=150, maxdelta=None, area=None, coolexp=1.5, repulserad=None, cellsize=None, **kwargs):

201

"""

202

Large Graph Layout (LGL) algorithm.

203

204

Parameters:

205

- weights: edge weights

206

- maxiter: int, maximum iterations

207

- maxdelta: float, maximum movement (None for automatic)

208

- area: float, layout area

209

- coolexp: float, cooling exponent

210

- repulserad: float, repulsion radius

211

- cellsize: float, cell size for spatial indexing

212

213

Returns:

214

Layout object

215

"""

216

```

217

218

**Usage Examples:**

219

220

```python

221

# Large network

222

large_g = ig.Graph.Barabasi(1000, m=3)

223

224

# DrL layout (good for large networks)

225

drl_layout = large_g.layout_drl()

226

227

# GraphOpt layout

228

graphopt_layout = large_g.layout_graphopt(niter=1000, node_charge=0.002)

229

230

# LGL layout

231

lgl_layout = large_g.layout_lgl(maxiter=200)

232

233

# For very large graphs, use fewer iterations

234

if large_g.vcount() > 5000:

235

quick_layout = large_g.layout_drl(dim=2) # Default parameters are efficient

236

```

237

238

### Geometric and Grid Layouts

239

240

Regular and geometric layout patterns for specific visualization needs.

241

242

```python { .api }

243

class Graph:

244

def layout_circle(self, order=None):

245

"""

246

Circular layout with vertices on a circle.

247

248

Parameters:

249

- order: list, vertex ordering (None for current order)

250

251

Returns:

252

Layout object with circular positioning

253

"""

254

255

def layout_grid(self, width=0, dim=2):

256

"""

257

Grid layout in regular pattern.

258

259

Parameters:

260

- width: int, grid width (0 for automatic square)

261

- dim: int, dimensions

262

263

Returns:

264

Layout object with grid positioning

265

"""

266

267

def layout_sphere(self):

268

"""

269

Spherical layout in 3D space.

270

271

Returns:

272

Layout object with 3D spherical coordinates

273

"""

274

275

def layout_random(self, dim=2):

276

"""

277

Random vertex positions.

278

279

Parameters:

280

- dim: int, dimensions

281

282

Returns:

283

Layout object with random coordinates

284

"""

285

286

def layout_fruchterman_reingold_3d(self, **kwargs):

287

"""

288

3D Fruchterman-Reingold layout (alias for layout_fruchterman_reingold(dim=3)).

289

290

Returns:

291

Layout object with 3D coordinates

292

"""

293

294

def layout_kamada_kawai_3d(self, **kwargs):

295

"""

296

3D Kamada-Kawai layout (alias for layout_kamada_kawai(dim=3)).

297

298

Returns:

299

Layout object with 3D coordinates

300

"""

301

302

def layout_random_3d(self, **kwargs):

303

"""

304

3D random layout (alias for layout_random(dim=3)).

305

306

Returns:

307

Layout object with 3D random coordinates

308

"""

309

310

def layout_grid_3d(self, **kwargs):

311

"""

312

3D grid layout (alias for layout_grid(dim=3)).

313

314

Returns:

315

Layout object with 3D grid coordinates

316

"""

317

```

318

319

**Usage Examples:**

320

321

```python

322

# Geometric layouts

323

g = ig.Graph.Ring(12)

324

325

# Circular layout

326

circle_layout = g.layout_circle()

327

328

# Custom vertex ordering for circle

329

vertex_order = list(range(0, 12, 2)) + list(range(1, 12, 2)) # Even then odd

330

ordered_circle = g.layout_circle(order=vertex_order)

331

332

# Grid layout

333

grid_g = ig.Graph.Lattice([4, 3]) # 4x3 grid graph

334

grid_layout = grid_g.layout_grid(width=4)

335

336

# 3D sphere

337

sphere_layout = g.layout_sphere()

338

339

# Random layout (useful as starting point)

340

random_layout = g.layout_random(dim=2)

341

```

342

343

### Multidimensional Scaling

344

345

Layouts based on preserving distances and similarities between vertices.

346

347

```python { .api }

348

class Graph:

349

def layout_mds(self, weights=None, dim=2, **kwargs):

350

"""

351

Multidimensional scaling layout.

352

353

Parameters:

354

- weights: edge weights for distance calculation

355

- dim: int, target dimensions

356

357

Returns:

358

Layout object preserving graph distances

359

"""

360

361

def layout_gem(self, weights=None, maxiter=40*40, temp_max=None, temp_min=None, temp_init=None):

362

"""

363

GEM (Graph EMbedder) layout algorithm.

364

365

Parameters:

366

- weights: edge weights

367

- maxiter: int, maximum iterations

368

- temp_max: float, maximum temperature

369

- temp_min: float, minimum temperature

370

- temp_init: float, initial temperature

371

372

Returns:

373

Layout object

374

"""

375

```

376

377

**Usage Examples:**

378

379

```python

380

# MDS layout (preserves shortest path distances)

381

mds_layout = g.layout_mds()

382

383

# With edge weights

384

g.es["weight"] = [abs(i-j) + 1 for i, j in g.get_edgelist()]

385

weighted_mds = g.layout_mds(weights="weight")

386

387

# GEM layout

388

gem_layout = g.layout_gem(maxiter=2000)

389

```

390

391

### Layout Manipulation

392

393

Methods for transforming, scaling, and adjusting existing layouts.

394

395

```python { .api }

396

class Layout:

397

def scale(self, *args):

398

"""

399

Scale layout coordinates.

400

401

Parameters:

402

- args: scaling factors (single value or per-dimension)

403

404

Returns:

405

None (modifies in place)

406

"""

407

408

def translate(self, *args):

409

"""

410

Translate layout coordinates.

411

412

Parameters:

413

- args: translation offsets

414

415

Returns:

416

None (modifies in place)

417

"""

418

419

def rotate(self, angle, dim1=0, dim2=1):

420

"""

421

Rotate layout in specified plane.

422

423

Parameters:

424

- angle: float, rotation angle in radians

425

- dim1, dim2: int, dimensions defining rotation plane

426

427

Returns:

428

None (modifies in place)

429

"""

430

431

def mirror(self, dim):

432

"""

433

Mirror layout along specified dimension.

434

435

Parameters:

436

- dim: int, dimension to mirror

437

438

Returns:

439

None (modifies in place)

440

"""

441

442

def fit_into(self, bbox, keep_aspect_ratio=True):

443

"""

444

Fit layout into bounding box.

445

446

Parameters:

447

- bbox: BoundingBox or (left, top, right, bottom)

448

- keep_aspect_ratio: bool, preserve proportions

449

450

Returns:

451

None (modifies in place)

452

"""

453

454

def copy(self):

455

"""

456

Create copy of layout.

457

458

Returns:

459

Layout, independent copy

460

"""

461

```

462

463

**Usage Examples:**

464

465

```python

466

from igraph.drawing import BoundingBox

467

import math

468

469

# Create and manipulate layout

470

layout = g.layout_fruchterman_reingold()

471

472

# Make a copy for manipulation

473

layout_copy = layout.copy()

474

475

# Scale by factor of 2

476

layout_copy.scale(2.0)

477

478

# Translate to center at origin

479

center_x = sum(pos[0] for pos in layout_copy) / len(layout_copy)

480

center_y = sum(pos[1] for pos in layout_copy) / len(layout_copy)

481

layout_copy.translate(-center_x, -center_y)

482

483

# Rotate 45 degrees

484

layout_copy.rotate(math.pi/4)

485

486

# Mirror horizontally

487

layout_copy.mirror(0)

488

489

# Fit into specific bounding box

490

bbox = BoundingBox(0, 0, 800, 600)

491

layout_copy.fit_into(bbox, keep_aspect_ratio=True)

492

493

# Different scaling per dimension

494

layout2 = layout.copy()

495

layout2.scale(1.5, 0.8) # Stretch horizontally, compress vertically

496

```

497

498

### Layout Comparison and Selection

499

500

Techniques for choosing appropriate layouts and comparing their quality.

501

502

**Usage Examples:**

503

504

```python

505

import time

506

507

# Compare layout algorithms for a specific graph

508

g = ig.Graph.Barabasi(100, m=3)

509

510

layouts = {}

511

times = {}

512

513

# Test different algorithms

514

algorithms = [

515

("fruchterman_reingold", g.layout_fruchterman_reingold),

516

("kamada_kawai", g.layout_kamada_kawai),

517

("drl", g.layout_drl),

518

("graphopt", g.layout_graphopt)

519

]

520

521

for name, method in algorithms:

522

start_time = time.time()

523

try:

524

layout = method()

525

layouts[name] = layout

526

times[name] = time.time() - start_time

527

print(f"{name}: {times[name]:.3f}s")

528

except Exception as e:

529

print(f"{name}: failed ({e})")

530

531

# Layout quality metrics (custom functions)

532

def layout_stress(graph, layout, weights=None):

533

"""Calculate layout stress (difference between graph and Euclidean distances)."""

534

import math

535

stress = 0

536

dist_matrix = graph.shortest_paths(weights=weights)

537

538

for i in range(len(layout)):

539

for j in range(i+1, len(layout)):

540

# Euclidean distance in layout

541

euclidean = math.sqrt(sum((layout[i][k] - layout[j][k])**2 for k in range(2)))

542

# Graph distance

543

graph_dist = dist_matrix[i][j]

544

if graph_dist != float('inf'):

545

stress += (euclidean - graph_dist) ** 2

546

return stress

547

548

# Evaluate layouts

549

for name, layout in layouts.items():

550

if layout:

551

stress = layout_stress(g, layout)

552

print(f"{name} stress: {stress:.2f}")

553

554

# Adaptive layout selection based on graph size

555

def choose_layout(graph):

556

"""Choose appropriate layout algorithm based on graph properties."""

557

n = graph.vcount()

558

m = graph.ecount()

559

560

if n <= 100:

561

return graph.layout_kamada_kawai()

562

elif n <= 1000:

563

return graph.layout_fruchterman_reingold()

564

else:

565

return graph.layout_drl()

566

567

optimal_layout = choose_layout(g)

568

```