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

data-types.mddocs/

0

# Core Data Types

1

2

Essential data structures including matrices, layouts, and utility classes that support graph operations and analysis. These foundational types enable efficient computation and data manipulation in igraph.

3

4

## Capabilities

5

6

### Matrix Operations

7

8

Simple matrix data type for coordinate pairs, adjacency matrices, and linear algebra operations.

9

10

```python { .api }

11

class Matrix:

12

def __init__(self, data=None, nrow=0, ncol=0):

13

"""

14

Create matrix from data or dimensions.

15

16

Parameters:

17

- data: list/nested list, matrix data

18

- nrow: int, number of rows (if data is flat list)

19

- ncol: int, number of columns (if data is flat list)

20

"""

21

22

@classmethod

23

def Fill(cls, value, shape):

24

"""

25

Create matrix filled with specific value.

26

27

Parameters:

28

- value: fill value

29

- shape: tuple (nrows, ncols)

30

31

Returns:

32

Matrix filled with value

33

"""

34

35

@classmethod

36

def Zero(cls, shape):

37

"""

38

Create zero matrix.

39

40

Parameters:

41

- shape: tuple (nrows, ncols)

42

43

Returns:

44

Matrix filled with zeros

45

"""

46

47

@classmethod

48

def Identity(cls, n):

49

"""

50

Create identity matrix.

51

52

Parameters:

53

- n: int, matrix size (n x n)

54

55

Returns:

56

Identity matrix

57

"""

58

59

def __getitem__(self, key):

60

"""Access matrix elements by [i, j] or [i]."""

61

62

def __setitem__(self, key, value):

63

"""Set matrix elements."""

64

65

@property

66

def shape(self):

67

"""Get matrix dimensions as (nrows, ncols)."""

68

69

def transpose(self):

70

"""

71

Get transposed matrix.

72

73

Returns:

74

Matrix, transposed version

75

"""

76

```

77

78

**Usage Examples:**

79

80

```python

81

from igraph.datatypes import Matrix

82

83

# Create matrix from nested list

84

data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

85

m1 = Matrix(data)

86

print(f"Matrix shape: {m1.shape}")

87

88

# Create from flat list with dimensions

89

flat_data = [1, 2, 3, 4, 5, 6]

90

m2 = Matrix(flat_data, nrow=2, ncol=3)

91

92

# Create special matrices

93

zero_matrix = Matrix.Zero((3, 3))

94

identity = Matrix.Identity(4)

95

filled = Matrix.Fill(7.5, (2, 4))

96

97

# Access elements

98

print(f"Element [1,2]: {m1[1, 2]}")

99

print(f"Row 0: {m1[0]}")

100

101

# Set elements

102

m1[0, 0] = 99

103

m1[2] = [10, 11, 12] # Set entire row

104

105

# Matrix operations

106

transposed = m1.transpose()

107

print(f"Original shape: {m1.shape}")

108

print(f"Transposed shape: {transposed.shape}")

109

110

# Use with graph operations

111

import igraph as ig

112

g = ig.Graph.Ring(5)

113

114

# Convert adjacency to Matrix

115

adj_list = g.get_adjacency()

116

adj_matrix = Matrix(adj_list)

117

print(f"Adjacency matrix shape: {adj_matrix.shape}")

118

```

119

120

### Layout Coordinates

121

122

Represents graph layout coordinates in n-dimensional space with transformation methods.

123

124

```python { .api }

125

class Layout:

126

def __init__(self, coords=None, dim=2):

127

"""

128

Create layout from coordinates.

129

130

Parameters:

131

- coords: list of tuples/lists, vertex coordinates

132

- dim: int, number of dimensions

133

"""

134

135

def __len__(self):

136

"""Get number of vertices in layout."""

137

138

def __getitem__(self, key):

139

"""Access coordinates by vertex index."""

140

141

def __setitem__(self, key, value):

142

"""Set coordinates for vertex."""

143

144

@property

145

def coords(self):

146

"""Get all coordinates as list of tuples."""

147

148

def copy(self):

149

"""

150

Create independent copy of layout.

151

152

Returns:

153

Layout, deep copy

154

"""

155

156

def scale(self, *args):

157

"""

158

Scale layout coordinates.

159

160

Parameters:

161

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

162

163

Returns:

164

None (modifies in place)

165

"""

166

167

def translate(self, *args):

168

"""

169

Translate layout coordinates.

170

171

Parameters:

172

- *args: translation offsets per dimension

173

174

Returns:

175

None (modifies in place)

176

"""

177

178

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

179

"""

180

Rotate layout in specified plane.

181

182

Parameters:

183

- angle: float, rotation angle in radians

184

- dim1, dim2: int, dimensions defining rotation plane

185

186

Returns:

187

None (modifies in place)

188

"""

189

190

def mirror(self, dim):

191

"""

192

Mirror layout along specified dimension.

193

194

Parameters:

195

- dim: int, dimension to mirror (0=x, 1=y, etc.)

196

197

Returns:

198

None (modifies in place)

199

"""

200

201

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

202

"""

203

Fit layout into bounding box.

204

205

Parameters:

206

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

207

- keep_aspect_ratio: bool, preserve proportions

208

209

Returns:

210

None (modifies in place)

211

"""

212

213

def centroid(self):

214

"""

215

Calculate layout centroid.

216

217

Returns:

218

tuple, center coordinates

219

"""

220

221

def boundaries(self):

222

"""

223

Get layout boundaries.

224

225

Returns:

226

tuple, (min_coords, max_coords) for each dimension

227

"""

228

```

229

230

**Usage Examples:**

231

232

```python

233

from igraph.layout import Layout

234

from igraph.drawing import BoundingBox

235

import math

236

237

# Create layout manually

238

coords = [(0, 0), (1, 0), (1, 1), (0, 1), (0.5, 0.5)]

239

layout = Layout(coords)

240

241

# Access and modify coordinates

242

print(f"Vertex 0 position: {layout[0]}")

243

layout[0] = (0.1, 0.1) # Move vertex slightly

244

245

# Layout transformations

246

layout_copy = layout.copy()

247

248

# Scale uniformly

249

layout_copy.scale(2.0) # Double all coordinates

250

251

# Scale per dimension

252

layout_copy.scale(1.5, 0.8) # Stretch x, compress y

253

254

# Translation

255

layout_copy.translate(10, 5) # Move right 10, up 5

256

257

# Rotation (45 degrees)

258

layout_copy.rotate(math.pi/4) # Rotate around origin

259

260

# Mirror horizontally

261

layout_copy.mirror(0) # Flip along x-axis

262

263

# Fit into bounding box

264

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

265

layout_copy.fit_into(bbox, keep_aspect_ratio=True)

266

267

# Layout analysis

268

centroid = layout.centroid()

269

boundaries = layout.boundaries()

270

print(f"Layout centroid: {centroid}")

271

print(f"Layout boundaries: {boundaries}")

272

273

# Create 3D layout

274

coords_3d = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]

275

layout_3d = Layout(coords_3d, dim=3)

276

277

# 3D rotation (around z-axis)

278

layout_3d.rotate(math.pi/6, dim1=0, dim2=1) # Rotate x-y plane

279

```

280

281

### Census and Analysis Results

282

283

Specialized data types for storing structural analysis results.

284

285

```python { .api }

286

class DyadCensus:

287

def __init__(self, mutual=0, asymmetric=0, null=0):

288

"""

289

Dyad census results for directed graphs.

290

291

Parameters:

292

- mutual: int, number of mutual dyads

293

- asymmetric: int, number of asymmetric dyads

294

- null: int, number of null dyads

295

"""

296

297

@property

298

def mutual(self):

299

"""Number of mutual dyads (edges in both directions)."""

300

301

@property

302

def asymmetric(self):

303

"""Number of asymmetric dyads (edge in one direction)."""

304

305

@property

306

def null(self):

307

"""Number of null dyads (no edges between vertices)."""

308

309

class TriadCensus:

310

def __init__(self, **kwargs):

311

"""

312

Triad census results with counts for all 16 triad types.

313

314

Triad types (MAN notation):

315

- 003: empty triad

316

- 012, 102, 021D, 021U, 021C: various asymmetric patterns

317

- 111D, 111U: mixed patterns

318

- 030T, 030C: transitive and cyclic triads

319

- 201: partially connected

320

- 120D, 120U, 120C: different orientations

321

- 210: almost complete

322

- 300: complete triad

323

"""

324

325

def __getattribute__(self, name):

326

"""Access triad counts by type name (e.g., census.003)."""

327

```

328

329

**Usage Examples:**

330

331

```python

332

import igraph as ig

333

334

# Dyad census for directed graph

335

g_dir = ig.Graph.Erdos_Renyi(20, 30, directed=True)

336

dyad_census = g_dir.dyad_census()

337

338

print(f"Mutual dyads: {dyad_census.mutual}")

339

print(f"Asymmetric dyads: {dyad_census.asymmetric}")

340

print(f"Null dyads: {dyad_census.null}")

341

print(f"Total possible dyads: {dyad_census.mutual + dyad_census.asymmetric + dyad_census.null}")

342

343

# Verify total

344

n = g_dir.vcount()

345

expected_total = n * (n - 1) // 2

346

print(f"Expected total: {expected_total}")

347

348

# Triad census

349

triad_census = g_dir.triad_census()

350

351

# Access specific triad types

352

print(f"Empty triads (003): {triad_census.__getattribute__('003')}")

353

print(f"Complete triads (300): {triad_census.__getattribute__('300')}")

354

print(f"Transitive triads (030T): {triad_census.__getattribute__('030T')}")

355

356

# Analyze triad distribution

357

triad_types = ['003', '012', '102', '021D', '021U', '021C',

358

'111D', '111U', '030T', '030C', '201',

359

'120D', '120U', '120C', '210', '300']

360

361

total_triads = 0

362

for triad_type in triad_types:

363

count = triad_census.__getattribute__(triad_type)

364

total_triads += count

365

if count > 0:

366

print(f"{triad_type}: {count}")

367

368

print(f"Total triads: {total_triads}")

369

expected_triads = n * (n - 1) * (n - 2) // 6

370

print(f"Expected total: {expected_triads}")

371

```

372

373

### Unique ID Generation

374

375

Dictionary-like class for assigning unique IDs to names or objects.

376

377

```python { .api }

378

class UniqueIdGenerator:

379

def __init__(self, id_generator=None, initial=None):

380

"""

381

Create unique ID generator.

382

383

Parameters:

384

- id_generator: function, custom ID generation function

385

- initial: dict, initial name-to-ID mappings

386

"""

387

388

def __getitem__(self, name):

389

"""

390

Get ID for name, creating new ID if needed.

391

392

Parameters:

393

- name: object, name/key to get ID for

394

395

Returns:

396

int, unique ID for name

397

"""

398

399

def __contains__(self, name):

400

"""Check if name already has assigned ID."""

401

402

def __len__(self):

403

"""Get number of assigned IDs."""

404

405

def keys(self):

406

"""Get all names with assigned IDs."""

407

408

def values(self):

409

"""Get all assigned ID values."""

410

411

def items(self):

412

"""Get (name, ID) pairs."""

413

414

def reverse_dict(self):

415

"""

416

Get reverse mapping from IDs to names.

417

418

Returns:

419

dict, ID-to-name mapping

420

"""

421

```

422

423

**Usage Examples:**

424

425

```python

426

from igraph.datatypes import UniqueIdGenerator

427

428

# Create ID generator for vertex names

429

id_gen = UniqueIdGenerator()

430

431

# Assign IDs to names

432

names = ["Alice", "Bob", "Carol", "Alice", "Dave", "Bob"]

433

vertex_ids = []

434

435

for name in names:

436

vertex_id = id_gen[name] # Gets existing ID or creates new one

437

vertex_ids.append(vertex_id)

438

439

print(f"Name to ID mapping: {list(id_gen.items())}")

440

print(f"Vertex IDs: {vertex_ids}") # [0, 1, 2, 0, 3, 1]

441

442

# Check if name exists

443

print(f"'Alice' has ID: {'Alice' in id_gen}")

444

print(f"'Eve' has ID: {'Eve' in id_gen}")

445

446

# Get reverse mapping

447

reverse = id_gen.reverse_dict()

448

print(f"ID to name: {reverse}")

449

450

# Use with custom ID generation

451

def custom_id_gen():

452

"""Generate IDs starting from 100."""

453

counter = 100

454

while True:

455

yield counter

456

counter += 1

457

458

custom_gen = UniqueIdGenerator(id_generator=custom_id_gen().__next__)

459

custom_gen["first"] = None # Triggers ID generation

460

custom_gen["second"] = None

461

print(f"Custom IDs: {list(custom_gen.items())}")

462

463

# Pre-populate with initial mappings

464

initial_map = {"root": 0, "admin": 1}

465

preset_gen = UniqueIdGenerator(initial=initial_map)

466

preset_gen["user1"] # Gets ID 2

467

preset_gen["user2"] # Gets ID 3

468

print(f"Preset generator: {list(preset_gen.items())}")

469

470

# Use in graph construction

471

def build_graph_from_edges(edge_list):

472

"""Build graph from string-based edge list."""

473

id_gen = UniqueIdGenerator()

474

numeric_edges = []

475

476

for source, target in edge_list:

477

source_id = id_gen[source]

478

target_id = id_gen[target]

479

numeric_edges.append((source_id, target_id))

480

481

g = ig.Graph(edges=numeric_edges, directed=False)

482

483

# Add vertex names

484

reverse_map = id_gen.reverse_dict()

485

g.vs["name"] = [reverse_map[i] for i in range(len(id_gen))]

486

487

return g

488

489

# Example usage

490

string_edges = [

491

("Alice", "Bob"),

492

("Bob", "Carol"),

493

("Carol", "Dave"),

494

("Alice", "Dave")

495

]

496

497

g = build_graph_from_edges(string_edges)

498

print(f"Graph vertices: {g.vs['name']}")

499

print(f"Graph edges: {g.get_edgelist()}")

500

```

501

502

### Geometric Utilities

503

504

Geometric classes for visualization and spatial operations.

505

506

```python { .api }

507

class BoundingBox:

508

def __init__(self, *args):

509

"""

510

Create bounding box.

511

512

Parameters:

513

- *args: (left, top, right, bottom) or ((left, top), (right, bottom))

514

"""

515

516

@property

517

def left(self):

518

"""Left coordinate."""

519

520

@property

521

def top(self):

522

"""Top coordinate."""

523

524

@property

525

def right(self):

526

"""Right coordinate."""

527

528

@property

529

def bottom(self):

530

"""Bottom coordinate."""

531

532

@property

533

def width(self):

534

"""Bounding box width."""

535

536

@property

537

def height(self):

538

"""Bounding box height."""

539

540

def area(self):

541

"""Calculate area."""

542

543

def contains(self, point):

544

"""Check if point is inside bounding box."""

545

546

class Point:

547

def __init__(self, x=0, y=0):

548

"""

549

Create 2D point.

550

551

Parameters:

552

- x, y: float, coordinates

553

"""

554

555

def distance(self, other):

556

"""Calculate distance to another point."""

557

558

class Rectangle:

559

def __init__(self, corner1, corner2=None, width=None, height=None):

560

"""

561

Create rectangle from corners or corner + dimensions.

562

563

Parameters:

564

- corner1: Point or tuple, first corner

565

- corner2: Point or tuple, opposite corner (OR use width/height)

566

- width: float, rectangle width

567

- height: float, rectangle height

568

"""

569

570

def area(self):

571

"""Calculate rectangle area."""

572

573

def contains(self, point):

574

"""Check if point is inside rectangle."""

575

```

576

577

**Usage Examples:**

578

579

```python

580

from igraph.drawing.utils import BoundingBox, Point, Rectangle

581

582

# Bounding box operations

583

bbox1 = BoundingBox(0, 0, 100, 80)

584

bbox2 = BoundingBox((10, 5), (90, 75)) # Alternative syntax

585

586

print(f"Box dimensions: {bbox1.width} x {bbox1.height}")

587

print(f"Box area: {bbox1.area()}")

588

589

# Point operations

590

p1 = Point(25, 30)

591

p2 = Point(75, 60)

592

593

distance = p1.distance(p2)

594

print(f"Distance between points: {distance:.2f}")

595

596

# Check containment

597

is_inside = bbox1.contains(p1)

598

print(f"Point {p1.x}, {p1.y} inside bbox: {is_inside}")

599

600

# Rectangle operations

601

rect1 = Rectangle(Point(10, 10), Point(50, 40))

602

rect2 = Rectangle(Point(20, 20), width=30, height=25)

603

604

print(f"Rectangle 1 area: {rect1.area()}")

605

print(f"Rectangle 2 contains (30, 30): {rect2.contains(Point(30, 30))}")

606

607

# Use in layout fitting

608

layout = ig.Graph.Ring(8).layout_circle()

609

target_bbox = BoundingBox(50, 50, 750, 550)

610

611

# Fit layout into bounding box

612

layout.fit_into(target_bbox, keep_aspect_ratio=True)

613

614

# Verify all points are within bounds

615

for i, (x, y) in enumerate(layout):

616

point = Point(x, y)

617

if not target_bbox.contains(point):

618

print(f"Point {i} outside bounds: ({x:.1f}, {y:.1f})")

619

```