or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

file-operations.mdgraph-management.mdgraph-utilities.mdindex.mdsubgraphs-clusters.md

subgraphs-clusters.mddocs/

0

# Subgraphs and Clusters

1

2

Advanced graph structuring with subgraphs and clusters for complex layouts, visual organization, and hierarchical graph representations. These features enable sophisticated graph designs with logical grouping and nested structures.

3

4

## Capabilities

5

6

### Subgraph Creation

7

8

Subgraphs provide logical grouping of nodes and edges within a parent graph, enabling hierarchical organization and layout control.

9

10

```python { .api }

11

class Subgraph:

12

def __init__(self, graph_name='', obj_dict=None, suppress_disconnected=False,

13

simplify=False, **attrs):

14

"""

15

Create a subgraph for logical grouping and layout control.

16

17

Parameters:

18

- graph_name (str): Name of the subgraph

19

- obj_dict (dict): Object dictionary for internal use

20

- suppress_disconnected (bool): Hide disconnected nodes in output

21

- simplify (bool): Remove redundant elements

22

- **attrs: Subgraph attributes

23

"""

24

25

def add_node(self, node):

26

"""Add a node to the subgraph."""

27

28

def add_edge(self, edge):

29

"""Add an edge to the subgraph."""

30

31

def get_nodes(self):

32

"""Get all nodes in the subgraph."""

33

34

def get_edges(self):

35

"""Get all edges in the subgraph."""

36

```

37

38

### Cluster Creation

39

40

Clusters are special subgraphs that provide visual grouping with borders and styling options. Cluster names must begin with 'cluster' to be recognized by Graphviz.

41

42

```python { .api }

43

class Cluster:

44

def __init__(self, graph_name='subG', obj_dict=None, suppress_disconnected=False,

45

simplify=False, **attrs):

46

"""

47

Create a cluster for visual grouping with borders.

48

49

Parameters:

50

- graph_name (str): Name of the cluster (should start with 'cluster')

51

- obj_dict (dict): Object dictionary for internal use

52

- suppress_disconnected (bool): Hide disconnected nodes in output

53

- simplify (bool): Remove redundant elements

54

- **attrs: Cluster attributes (bgcolor, style, etc.)

55

"""

56

```

57

58

### Cluster Attribute Methods

59

60

Clusters support dynamically generated attribute methods for visual styling:

61

62

```python { .api }

63

# Visual styling methods (22 attributes)

64

def get_bgcolor(self): """Get background color."""

65

def set_bgcolor(self, value): """Set background color."""

66

67

def get_color(self): """Get border color."""

68

def set_color(self, value): """Set border color."""

69

70

def get_style(self): """Get cluster style."""

71

def set_style(self, value): """Set cluster style ('filled', 'rounded', etc.)."""

72

73

def get_label(self): """Get cluster label."""

74

def set_label(self, value): """Set cluster label."""

75

76

def get_fontname(self): """Get font family."""

77

def set_fontname(self, value): """Set font family."""

78

79

def get_fontsize(self): """Get font size."""

80

def set_fontsize(self, value): """Set font size."""

81

82

def get_penwidth(self): """Get border line width."""

83

def set_penwidth(self, value): """Set border line width."""

84

```

85

86

### Integration with Parent Graphs

87

88

Both subgraphs and clusters integrate seamlessly with parent graphs:

89

90

```python { .api }

91

# In Dot/Graph classes:

92

def add_subgraph(self, subgraph):

93

"""Add a subgraph to the parent graph."""

94

95

def get_subgraphs(self):

96

"""Get all subgraphs in the graph."""

97

```

98

99

## Usage Examples

100

101

### Creating Subgraphs for Layout Control

102

103

```python

104

import pydot

105

106

# Create main graph

107

main_graph = pydot.Dot("hierarchical", graph_type="digraph")

108

109

# Create subgraph for input nodes

110

input_subgraph = pydot.Subgraph("inputs")

111

input_subgraph.set_rank("same") # Align nodes horizontally

112

113

input_a = pydot.Node("input_a", label="Input A", shape="ellipse")

114

input_b = pydot.Node("input_b", label="Input B", shape="ellipse")

115

input_subgraph.add_node(input_a)

116

input_subgraph.add_node(input_b)

117

118

# Create subgraph for processing nodes

119

processing_subgraph = pydot.Subgraph("processing")

120

processing_subgraph.set_rank("same")

121

122

process_x = pydot.Node("process_x", label="Process X", shape="box")

123

process_y = pydot.Node("process_y", label="Process Y", shape="box")

124

processing_subgraph.add_node(process_x)

125

processing_subgraph.add_node(process_y)

126

127

# Add subgraphs to main graph

128

main_graph.add_subgraph(input_subgraph)

129

main_graph.add_subgraph(processing_subgraph)

130

131

# Add cross-subgraph edges

132

main_graph.add_edge(pydot.Edge("input_a", "process_x"))

133

main_graph.add_edge(pydot.Edge("input_b", "process_y"))

134

135

main_graph.write_png("hierarchical_layout.png")

136

```

137

138

### Creating Visual Clusters

139

140

```python

141

import pydot

142

143

# Create main graph

144

system_graph = pydot.Dot("system_architecture", graph_type="digraph")

145

146

# Create cluster for database layer

147

db_cluster = pydot.Cluster("cluster_database")

148

db_cluster.set_label("Database Layer")

149

db_cluster.set_bgcolor("lightblue")

150

db_cluster.set_style("filled")

151

db_cluster.set_color("blue")

152

153

# Add database components

154

db_cluster.add_node(pydot.Node("mysql", label="MySQL", shape="cylinder"))

155

db_cluster.add_node(pydot.Node("redis", label="Redis Cache", shape="cylinder"))

156

157

# Create cluster for application layer

158

app_cluster = pydot.Cluster("cluster_application")

159

app_cluster.set_label("Application Layer")

160

app_cluster.set_bgcolor("lightgreen")

161

app_cluster.set_style("filled")

162

app_cluster.set_color("green")

163

164

app_cluster.add_node(pydot.Node("api", label="REST API", shape="box"))

165

app_cluster.add_node(pydot.Node("worker", label="Background Worker", shape="box"))

166

167

# Create cluster for presentation layer

168

ui_cluster = pydot.Cluster("cluster_ui")

169

ui_cluster.set_label("Presentation Layer")

170

ui_cluster.set_bgcolor("lightyellow")

171

ui_cluster.set_style("filled")

172

ui_cluster.set_color("orange")

173

174

ui_cluster.add_node(pydot.Node("web", label="Web App", shape="note"))

175

ui_cluster.add_node(pydot.Node("mobile", label="Mobile App", shape="note"))

176

177

# Add clusters to main graph

178

system_graph.add_subgraph(db_cluster)

179

system_graph.add_subgraph(app_cluster)

180

system_graph.add_subgraph(ui_cluster)

181

182

# Add inter-cluster connections

183

system_graph.add_edge(pydot.Edge("api", "mysql", label="queries"))

184

system_graph.add_edge(pydot.Edge("api", "redis", label="cache"))

185

system_graph.add_edge(pydot.Edge("web", "api", label="HTTP"))

186

system_graph.add_edge(pydot.Edge("mobile", "api", label="HTTP"))

187

system_graph.add_edge(pydot.Edge("worker", "mysql", label="updates"))

188

189

system_graph.set_rankdir("TB") # Top to bottom layout

190

system_graph.write_png("system_architecture.png")

191

```

192

193

### Nested Subgraphs

194

195

```python

196

import pydot

197

198

# Create main organizational chart

199

org_chart = pydot.Dot("organization", graph_type="digraph")

200

201

# Engineering department cluster

202

engineering = pydot.Cluster("cluster_engineering")

203

engineering.set_label("Engineering Department")

204

engineering.set_bgcolor("lightcyan")

205

engineering.set_style("filled")

206

207

# Frontend team subgraph within engineering

208

frontend_team = pydot.Subgraph("frontend_team")

209

frontend_team.set_rank("same")

210

frontend_team.add_node(pydot.Node("fe_lead", label="Frontend Lead", shape="box"))

211

frontend_team.add_node(pydot.Node("fe_dev1", label="Frontend Dev 1", shape="ellipse"))

212

frontend_team.add_node(pydot.Node("fe_dev2", label="Frontend Dev 2", shape="ellipse"))

213

214

# Backend team subgraph within engineering

215

backend_team = pydot.Subgraph("backend_team")

216

backend_team.set_rank("same")

217

backend_team.add_node(pydot.Node("be_lead", label="Backend Lead", shape="box"))

218

backend_team.add_node(pydot.Node("be_dev1", label="Backend Dev 1", shape="ellipse"))

219

backend_team.add_node(pydot.Node("be_dev2", label="Backend Dev 2", shape="ellipse"))

220

221

# Add teams to engineering cluster

222

engineering.add_subgraph(frontend_team)

223

engineering.add_subgraph(backend_team)

224

225

# Add engineering head

226

engineering.add_node(pydot.Node("eng_director", label="Engineering Director",

227

shape="doubleoctagon", style="filled", fillcolor="gold"))

228

229

# Add to main chart

230

org_chart.add_subgraph(engineering)

231

232

# Add reporting relationships

233

org_chart.add_edge(pydot.Edge("eng_director", "fe_lead", style="dashed"))

234

org_chart.add_edge(pydot.Edge("eng_director", "be_lead", style="dashed"))

235

org_chart.add_edge(pydot.Edge("fe_lead", "fe_dev1"))

236

org_chart.add_edge(pydot.Edge("fe_lead", "fe_dev2"))

237

org_chart.add_edge(pydot.Edge("be_lead", "be_dev1"))

238

org_chart.add_edge(pydot.Edge("be_lead", "be_dev2"))

239

240

org_chart.write_png("org_chart.png")

241

```

242

243

### Subgraph Layout Control

244

245

```python

246

import pydot

247

248

# Create process flow with controlled layout

249

process_flow = pydot.Dot("process", graph_type="digraph")

250

251

# Group parallel processes

252

parallel_processes = pydot.Subgraph("parallel")

253

parallel_processes.set_rank("same") # Align horizontally

254

255

parallel_processes.add_node(pydot.Node("task_a", label="Task A"))

256

parallel_processes.add_node(pydot.Node("task_b", label="Task B"))

257

parallel_processes.add_node(pydot.Node("task_c", label="Task C"))

258

259

process_flow.add_subgraph(parallel_processes)

260

261

# Add sequential nodes

262

process_flow.add_node(pydot.Node("start", label="Start", shape="ellipse"))

263

process_flow.add_node(pydot.Node("merge", label="Merge Results", shape="diamond"))

264

process_flow.add_node(pydot.Node("end", label="End", shape="ellipse"))

265

266

# Connect the flow

267

process_flow.add_edge(pydot.Edge("start", "task_a"))

268

process_flow.add_edge(pydot.Edge("start", "task_b"))

269

process_flow.add_edge(pydot.Edge("start", "task_c"))

270

process_flow.add_edge(pydot.Edge("task_a", "merge"))

271

process_flow.add_edge(pydot.Edge("task_b", "merge"))

272

process_flow.add_edge(pydot.Edge("task_c", "merge"))

273

process_flow.add_edge(pydot.Edge("merge", "end"))

274

275

process_flow.write_png("process_flow.png")

276

```