or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdnode-operations.mdtree-analysis.mdtree-io.mdtree-manipulation.mdtree-traversal.mdvisualization.md

node-operations.mddocs/

0

# Node Operations

1

2

TreeSwift Node objects represent individual tree nodes with parent-child relationships, labels, and edge lengths. Node operations provide fine-grained control over tree structure and enable custom tree construction and manipulation algorithms.

3

4

## Capabilities

5

6

### Node Creation and Properties

7

8

Create and inspect individual nodes with their basic properties.

9

10

```python { .api }

11

class Node:

12

"""Individual tree node with parent-child relationships."""

13

14

def __init__(self, label: object = None, edge_length: float = None) -> None:

15

"""

16

Create a new Node.

17

18

Parameters:

19

- label (object): Node label (any object, typically string)

20

- edge_length (float): Length of edge leading to this node

21

"""

22

23

def __str__(self) -> str:

24

"""String representation of node (returns label as string)."""

25

26

def __copy__(self) -> Node:

27

"""Create a copy of this node."""

28

29

def __lt__(self, other: Node) -> bool:

30

"""Less than comparison based on labels."""

31

```

32

33

Usage examples:

34

35

```python

36

import treeswift

37

38

# Create nodes

39

root = treeswift.Node()

40

leaf_a = treeswift.Node(label="A", edge_length=0.1)

41

leaf_b = treeswift.Node(label="B", edge_length=0.2)

42

43

print(f"Root: {root}") # Empty string (no label)

44

print(f"Leaf A: {leaf_a}") # "A"

45

print(f"Leaf B: {leaf_b}") # "B"

46

47

# Copy nodes

48

leaf_a_copy = leaf_a.__copy__()

49

print(f"Original: {leaf_a.get_label()}, Copy: {leaf_a_copy.get_label()}")

50

51

# Compare nodes

52

nodes = [treeswift.Node(label="C"), treeswift.Node(label="A"), treeswift.Node(label="B")]

53

sorted_nodes = sorted(nodes)

54

print(f"Sorted labels: {[str(n) for n in sorted_nodes]}")

55

```

56

57

### Parent-Child Relationships

58

59

Manage the hierarchical structure of nodes through parent-child relationships.

60

61

```python { .api }

62

def add_child(self, child: Node) -> None:

63

"""

64

Add child to this node.

65

66

Parameters:

67

- child (Node): Child node to add

68

"""

69

70

def remove_child(self, child: Node) -> None:

71

"""

72

Remove child from this node.

73

74

Parameters:

75

- child (Node): Child node to remove

76

77

Raises:

78

- RuntimeError: If child is not found

79

"""

80

81

def child_nodes(self) -> list[Node]:

82

"""

83

Get list of child nodes.

84

85

Returns:

86

- list[Node]: Copy of children list

87

"""

88

89

def get_parent(self) -> Node | None:

90

"""

91

Get parent node.

92

93

Returns:

94

- Node | None: Parent node (None if root)

95

"""

96

97

def set_parent(self, parent: Node) -> None:

98

"""

99

Set parent node (use carefully to avoid breaking tree structure).

100

101

Parameters:

102

- parent (Node): New parent node

103

"""

104

```

105

106

Usage examples:

107

108

```python

109

import treeswift

110

111

# Build tree structure manually

112

root = treeswift.Node()

113

internal = treeswift.Node(edge_length=0.1)

114

leaf_a = treeswift.Node(label="A", edge_length=0.2)

115

leaf_b = treeswift.Node(label="B", edge_length=0.3)

116

117

# Construct tree

118

root.add_child(internal)

119

internal.add_child(leaf_a)

120

internal.add_child(leaf_b)

121

122

# Inspect relationships

123

print(f"Root children: {len(root.child_nodes())}")

124

print(f"Internal node parent is root: {internal.get_parent() == root}")

125

print(f"Leaf A parent: {leaf_a.get_parent() == internal}")

126

127

# Modify structure

128

leaf_c = treeswift.Node(label="C", edge_length=0.4)

129

internal.add_child(leaf_c)

130

print(f"Internal node now has {len(internal.child_nodes())} children")

131

132

# Remove child

133

internal.remove_child(leaf_c)

134

print(f"After removal: {len(internal.child_nodes())} children")

135

```

136

137

### Node Properties and Status

138

139

Query node properties and structural status within the tree.

140

141

```python { .api }

142

def is_leaf(self) -> bool:

143

"""

144

Check if node is a leaf (no children).

145

146

Returns:

147

- bool: True if leaf, False otherwise

148

"""

149

150

def is_root(self) -> bool:

151

"""

152

Check if node is root (no parent).

153

154

Returns:

155

- bool: True if root, False otherwise

156

"""

157

158

def num_children(self) -> int:

159

"""

160

Get number of children.

161

162

Returns:

163

- int: Number of child nodes

164

"""

165

166

def num_nodes(self, leaves: bool = True, internal: bool = True) -> int:

167

"""

168

Count nodes in subtree rooted at this node.

169

170

Parameters:

171

- leaves (bool): Include leaf nodes in count

172

- internal (bool): Include internal nodes in count

173

174

Returns:

175

- int: Number of selected nodes in subtree

176

"""

177

```

178

179

Usage examples:

180

181

```python

182

import treeswift

183

184

# Create tree structure

185

tree = treeswift.read_tree_newick("((A,B),(C,D));")

186

187

# Check node properties

188

for node in tree.traverse_preorder():

189

label = node.get_label() or "internal"

190

status = []

191

192

if node.is_root():

193

status.append("root")

194

if node.is_leaf():

195

status.append("leaf")

196

197

print(f"{label}: {', '.join(status) if status else 'internal'}")

198

print(f" Children: {node.num_children()}")

199

200

if not node.is_leaf():

201

subtree_size = node.num_nodes()

202

leaf_count = node.num_nodes(internal=False)

203

internal_count = node.num_nodes(leaves=False)

204

print(f" Subtree: {subtree_size} total, {leaf_count} leaves, {internal_count} internal")

205

```

206

207

### Label Management

208

209

Get and set node labels with flexible typing support.

210

211

```python { .api }

212

def get_label(self) -> object:

213

"""

214

Get node label.

215

216

Returns:

217

- object: Node label (any type, None if not set)

218

"""

219

220

def set_label(self, label: object) -> None:

221

"""

222

Set node label.

223

224

Parameters:

225

- label (object): New label (any type)

226

"""

227

```

228

229

Usage examples:

230

231

```python

232

import treeswift

233

234

# Work with different label types

235

node1 = treeswift.Node()

236

node2 = treeswift.Node()

237

node3 = treeswift.Node()

238

239

# String labels

240

node1.set_label("Species_A")

241

print(f"String label: {node1.get_label()}")

242

243

# Numeric labels

244

node2.set_label(42)

245

print(f"Numeric label: {node2.get_label()}")

246

247

# Complex object labels

248

node3.set_label({"species": "Homo sapiens", "confidence": 0.95})

249

print(f"Dict label: {node3.get_label()}")

250

251

# None labels

252

node4 = treeswift.Node()

253

print(f"No label: {node4.get_label()}")

254

print(f"String representation: '{node4}'")

255

```

256

257

### Edge Length Management

258

259

Manage branch lengths associated with nodes.

260

261

```python { .api }

262

def get_edge_length(self) -> float | None:

263

"""

264

Get edge length leading to this node.

265

266

Returns:

267

- float | None: Edge length (None if not set)

268

"""

269

270

def set_edge_length(self, length: float) -> None:

271

"""

272

Set edge length leading to this node.

273

274

Parameters:

275

- length (float): Edge length (must be convertible to float)

276

277

Raises:

278

- TypeError: If length cannot be converted to float

279

"""

280

```

281

282

Usage examples:

283

284

```python

285

import treeswift

286

287

# Edge length operations

288

node = treeswift.Node(label="A")

289

290

# Initially no edge length

291

print(f"Initial edge length: {node.get_edge_length()}")

292

293

# Set edge length

294

node.set_edge_length(0.123)

295

print(f"Set edge length: {node.get_edge_length()}")

296

297

# Update edge length

298

node.set_edge_length(0.456)

299

print(f"Updated edge length: {node.get_edge_length()}")

300

301

# Edge length type conversion

302

node.set_edge_length("0.789") # String converted to float

303

print(f"From string: {node.get_edge_length()}")

304

305

node.set_edge_length(1) # Integer converted to float

306

print(f"From integer: {node.get_edge_length()}")

307

308

# Error handling

309

try:

310

node.set_edge_length("invalid")

311

except TypeError as e:

312

print(f"Error: {e}")

313

```

314

315

### Node Structural Operations

316

317

Modify node structure and resolve local tree issues.

318

319

```python { .api }

320

def contract(self) -> None:

321

"""Contract this node by connecting children directly to parent."""

322

323

def resolve_polytomies(self) -> None:

324

"""Resolve polytomies below this node using zero-length edges."""

325

```

326

327

Usage examples:

328

329

```python

330

import treeswift

331

332

# Contract node example

333

tree = treeswift.read_tree_newick("(((A,B),C),D);")

334

print(f"Before contraction: {tree.newick()}")

335

336

# Find internal node to contract

337

for node in tree.traverse_internal():

338

if node.num_children() == 1: # Unifurcation

339

node.contract() # Remove this node

340

break

341

342

print(f"After contraction: {tree.newick()}")

343

344

# Resolve polytomies at node level

345

tree = treeswift.Tree()

346

root = tree.root

347

for label in ["A", "B", "C", "D"]:

348

child = treeswift.Node(label=label, edge_length=0.1)

349

root.add_child(child)

350

351

print(f"Polytomy: {tree.newick()}")

352

root.resolve_polytomies() # Resolve only below this node

353

print(f"Resolved: {tree.newick()}")

354

```

355

356

### Node Output Formatting

357

358

Generate string representations of subtrees rooted at nodes.

359

360

```python { .api }

361

def newick(self) -> str:

362

"""

363

Generate Newick string for subtree rooted at this node.

364

365

Returns:

366

- str: Newick representation of subtree

367

"""

368

```

369

370

Usage examples:

371

372

```python

373

import treeswift

374

375

# Generate subtree Newick strings

376

tree = treeswift.read_tree_newick("((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6);")

377

378

print(f"Full tree: {tree.newick()}")

379

380

# Get Newick for each subtree

381

for node in tree.traverse_internal():

382

if node != tree.root:

383

subtree_newick = node.newick()

384

print(f"Subtree with {node.num_children()} children: {subtree_newick}")

385

386

# Single node Newick

387

for leaf in tree.traverse_leaves():

388

leaf_newick = leaf.newick()

389

print(f"Leaf {leaf.get_label()}: {leaf_newick}")

390

```

391

392

### Node Attributes Access

393

394

Direct access to node attributes (use with caution).

395

396

```python { .api }

397

# Node attributes (direct access)

398

children: list[Node] # List of child nodes

399

parent: Node | None # Parent node (None for root)

400

label: object # Node label

401

edge_length: float | None # Edge length

402

```

403

404

Usage examples:

405

406

```python

407

import treeswift

408

409

# Direct attribute access (advanced usage)

410

node = treeswift.Node(label="test", edge_length=0.5)

411

412

# Access attributes directly

413

print(f"Label: {node.label}")

414

print(f"Edge length: {node.edge_length}")

415

print(f"Children list: {node.children}")

416

print(f"Parent: {node.parent}")

417

418

# Modify attributes directly (be careful!)

419

node.label = "modified_label"

420

node.edge_length = 1.0

421

422

# Add to tree

423

tree = treeswift.Tree()

424

tree.root.children.append(node) # Direct list manipulation

425

node.parent = tree.root # Set parent reference

426

427

print(f"Tree: {tree.newick()}")

428

```