0
# Graph Visualization
1
2
Generate visual representations of object reference graphs using graphviz. These functions create diagrams showing how objects reference each other, essential for understanding memory layouts, debugging circular references, and visualizing object relationships.
3
4
## Capabilities
5
6
### Backward Reference Visualization
7
8
Generate graphs showing what objects refer to the target objects.
9
10
```python { .api }
11
def show_backrefs(objs, max_depth=3, extra_ignore=(), filter=None, too_many=10, highlight=None, filename=None, extra_info=None, refcounts=False, shortnames=True, output=None, extra_node_attrs=None):
12
"""
13
Generate an object reference graph ending at objs.
14
15
Args:
16
objs: Single object or list of objects to analyze
17
max_depth (int): Maximum graph depth to traverse
18
extra_ignore (tuple): Object IDs to ignore in the graph
19
filter (callable, optional): Function taking object and returning bool; objects returning False are excluded
20
too_many (int): Limit for references per object before truncating
21
highlight (callable, optional): Function taking object and returning bool; matching objects highlighted in blue
22
filename (str, optional): Output file name (.dot, .png, .svg, etc.)
23
extra_info (callable, optional): Function taking object and returning string for extra node information
24
refcounts (bool): Show reference counts in node labels
25
shortnames (bool): Use short class names vs fully qualified names
26
output (file-like, optional): File object to write GraphViz output
27
extra_node_attrs (callable, optional): Function taking object and returning dict of GraphViz node attributes
28
29
Returns:
30
None or graphviz.Source: None for file output, Source object for interactive display
31
32
Note:
33
Shows what refers to the objects. Automatically stops at proper modules to avoid clutter.
34
Cannot specify both filename and output parameters (raises ValueError).
35
"""
36
```
37
38
Usage examples:
39
40
```python
41
import objgraph
42
43
# Basic backref visualization
44
my_object = [1, 2, 3]
45
objgraph.show_backrefs([my_object]) # Interactive display or xdot
46
47
# Save to file
48
objgraph.show_backrefs([my_object], filename='my_backrefs.png')
49
50
# Multiple objects
51
obj1 = {'key': 'value'}
52
obj2 = [1, 2, 3]
53
objgraph.show_backrefs([obj1, obj2], filename='multi_backrefs.png')
54
55
# Advanced filtering
56
def is_interesting(obj):
57
return not isinstance(obj, (str, int, float, bool, type(None)))
58
59
objgraph.show_backrefs([my_object],
60
filter=is_interesting,
61
max_depth=5,
62
filename='filtered_backrefs.png')
63
64
# Highlight specific objects
65
import types
66
objgraph.show_backrefs([my_object],
67
highlight=lambda x: isinstance(x, types.ModuleType),
68
filename='highlighted_backrefs.png')
69
70
# Show reference counts
71
objgraph.show_backrefs([my_object],
72
refcounts=True,
73
filename='refcount_backrefs.png')
74
75
# Fully qualified names
76
objgraph.show_backrefs([my_object],
77
shortnames=False,
78
filename='qualified_backrefs.png')
79
80
# Custom extra info
81
def show_size(obj):
82
if hasattr(obj, '__len__'):
83
return f"size: {len(obj)}"
84
return ""
85
86
objgraph.show_backrefs([my_object],
87
extra_info=show_size,
88
filename='size_info_backrefs.png')
89
90
# Output to file object
91
import io
92
output_buffer = io.StringIO()
93
objgraph.show_backrefs([my_object], output=output_buffer)
94
dot_content = output_buffer.getvalue()
95
96
# Custom node attributes
97
def node_attrs(obj):
98
if isinstance(obj, list):
99
return {'color': 'red', 'style': 'bold'}
100
return {}
101
102
objgraph.show_backrefs([my_object],
103
extra_node_attrs=node_attrs,
104
filename='custom_attrs_backrefs.png')
105
```
106
107
### Forward Reference Visualization
108
109
Generate graphs showing what objects the target objects refer to.
110
111
```python { .api }
112
def show_refs(objs, max_depth=3, extra_ignore=(), filter=None, too_many=10, highlight=None, filename=None, extra_info=None, refcounts=False, shortnames=True, output=None, extra_node_attrs=None):
113
"""
114
Generate an object reference graph starting at objs.
115
116
Args:
117
objs: Single object or list of objects to analyze
118
max_depth (int): Maximum graph depth to traverse
119
extra_ignore (tuple): Object IDs to ignore in the graph
120
filter (callable, optional): Function taking object and returning bool; objects returning False are excluded
121
too_many (int): Limit for references per object before truncating
122
highlight (callable, optional): Function taking object and returning bool; matching objects highlighted in blue
123
filename (str, optional): Output file name (.dot, .png, .svg, etc.)
124
extra_info (callable, optional): Function taking object and returning string for extra node information
125
refcounts (bool): Show reference counts in node labels
126
shortnames (bool): Use short class names vs fully qualified names
127
output (file-like, optional): File object to write GraphViz output
128
extra_node_attrs (callable, optional): Function taking object and returning dict of GraphViz node attributes
129
130
Returns:
131
None or graphviz.Source: None for file output, Source object for interactive display
132
133
Note:
134
Shows what the objects refer to. Follows references from modules (unlike show_backrefs).
135
Cannot specify both filename and output parameters (raises ValueError).
136
"""
137
```
138
139
Usage examples:
140
141
```python
142
import objgraph
143
144
# Basic forward reference visualization
145
class MyClass:
146
def __init__(self):
147
self.data = [1, 2, 3]
148
self.info = {'status': 'active'}
149
150
obj = MyClass()
151
objgraph.show_refs([obj], filename='forward_refs.png')
152
153
# Show what a complex object contains
154
complex_structure = {
155
'lists': [[1, 2], [3, 4], [5, 6]],
156
'nested': {'inner': {'deep': 'value'}},
157
'function': lambda x: x * 2
158
}
159
objgraph.show_refs([complex_structure],
160
max_depth=4,
161
filename='complex_refs.png')
162
163
# Filter out built-in types
164
def is_custom(obj):
165
return not isinstance(obj, (str, int, float, bool, type(None)))
166
167
objgraph.show_refs([obj],
168
filter=is_custom,
169
filename='custom_only_refs.png')
170
171
# Highlight containers
172
objgraph.show_refs([obj],
173
highlight=lambda x: hasattr(x, '__len__'),
174
filename='highlighted_containers.png')
175
176
# Limit references to avoid cluttered graphs
177
large_object = {'key_' + str(i): f'value_{i}' for i in range(100)}
178
objgraph.show_refs([large_object],
179
too_many=5, # Only show first 5 references
180
filename='limited_refs.png')
181
```
182
183
### Reference Chain Visualization
184
185
Display specific reference chains found with find_ref_chain or find_backref_chain.
186
187
```python { .api }
188
def show_chain(*chains, **kw):
189
"""
190
Show a chain (or several chains) of object references.
191
192
Args:
193
*chains: One or more reference chains (lists of objects)
194
backrefs (bool, keyword): If True, trace backwards; if False, trace forwards (default: True)
195
highlight (callable, keyword): Function taking object and returning bool for highlighting
196
extra_info (callable, keyword): Function taking object and returning string for extra info
197
refcounts (bool, keyword): Show reference counts in node labels
198
shortnames (bool, keyword): Use short class names vs fully qualified names
199
filename (str, keyword): Output file name (.dot, .png, .svg, etc.)
200
output (file-like, keyword): File object to write GraphViz output to
201
202
Returns:
203
None or graphviz.Source: None for file output, Source object for interactive display
204
205
Note:
206
Useful with find_ref_chain() or find_backref_chain().
207
Filters the graph to show only objects in the provided chains.
208
"""
209
```
210
211
Usage examples:
212
213
```python
214
import objgraph
215
216
# Find and visualize a chain
217
my_object = [1, 2, 3]
218
globals()['my_global'] = my_object # Ensure it's reachable from a module
219
220
chain = objgraph.find_backref_chain(my_object, objgraph.is_proper_module)
221
objgraph.show_chain(chain, filename='backref_chain.png')
222
223
# Multiple chains
224
obj1 = [1, 2, 3]
225
obj2 = {'key': 'value'}
226
globals()['obj1'] = obj1
227
globals()['obj2'] = obj2
228
229
chain1 = objgraph.find_backref_chain(obj1, objgraph.is_proper_module)
230
chain2 = objgraph.find_backref_chain(obj2, objgraph.is_proper_module)
231
objgraph.show_chain(chain1, chain2, filename='multiple_chains.png')
232
233
# Forward chain visualization
234
target_obj = [1, 2, 3]
235
container = {'target': target_obj}
236
forward_chain = objgraph.find_ref_chain(container, lambda x: isinstance(x, list))
237
objgraph.show_chain(forward_chain, backrefs=False, filename='forward_chain.png')
238
239
# Chain with highlighting
240
objgraph.show_chain(chain,
241
highlight=lambda x: isinstance(x, dict),
242
filename='highlighted_chain.png')
243
244
# Chain with extra info
245
def show_type_and_size(obj):
246
type_name = type(obj).__name__
247
if hasattr(obj, '__len__'):
248
return f"{type_name} (size: {len(obj)})"
249
return type_name
250
251
objgraph.show_chain(chain,
252
extra_info=show_type_and_size,
253
filename='detailed_chain.png')
254
```
255
256
## Output Formats and Viewing
257
258
objgraph supports multiple output formats and viewing methods:
259
260
### File Formats
261
262
```python
263
# PNG images (most common)
264
objgraph.show_backrefs([obj], filename='graph.png')
265
266
# SVG for scalable graphics
267
objgraph.show_backrefs([obj], filename='graph.svg')
268
269
# PDF for high-quality printing
270
objgraph.show_backrefs([obj], filename='graph.pdf')
271
272
# Raw GraphViz DOT format
273
objgraph.show_backrefs([obj], filename='graph.dot')
274
275
# Format determined by extension
276
objgraph.show_backrefs([obj], filename='graph.jpg') # JPEG
277
```
278
279
### Interactive Viewing
280
281
```python
282
# Automatic viewing (tries xdot, then generates PNG)
283
objgraph.show_backrefs([obj])
284
285
# IPython/Jupyter inline display
286
# (returns graphviz.Source object when IS_INTERACTIVE=True)
287
result = objgraph.show_backrefs([obj])
288
# result can be displayed inline in notebooks
289
```
290
291
## Common Workflows
292
293
### Memory Leak Visualization
294
295
```python
296
import objgraph
297
import gc
298
299
# Find objects that might be leaking
300
gc.collect()
301
before_count = objgraph.count('MyClass')
302
303
# Run code that might create objects
304
for i in range(100):
305
# some_operation_that_might_leak()
306
pass
307
308
gc.collect()
309
after_count = objgraph.count('MyClass')
310
311
if after_count > before_count:
312
print(f"Potential leak: {after_count - before_count} new MyClass objects")
313
314
# Get some instances to investigate
315
instances = objgraph.by_type('MyClass')
316
recent_instances = instances[before_count:before_count + 5] # First 5 new ones
317
318
# Show what keeps them alive
319
objgraph.show_backrefs(recent_instances,
320
max_depth=5,
321
filename='potential_leak.png')
322
```
323
324
### Complex Object Structure Analysis
325
326
```python
327
import objgraph
328
329
# Analyze a complex data structure
330
class Node:
331
def __init__(self, value):
332
self.value = value
333
self.children = []
334
self.metadata = {}
335
336
def add_child(self, child):
337
self.children.append(child)
338
child.metadata['parent'] = self
339
340
# Create complex structure
341
root = Node("root")
342
for i in range(3):
343
child = Node(f"child_{i}")
344
root.add_child(child)
345
for j in range(2):
346
grandchild = Node(f"grandchild_{i}_{j}")
347
child.add_child(grandchild)
348
349
# Visualize the structure
350
objgraph.show_refs([root],
351
max_depth=4,
352
highlight=lambda x: isinstance(x, Node),
353
extra_info=lambda x: getattr(x, 'value', ''),
354
filename='tree_structure.png')
355
356
# Show what keeps leaf nodes alive
357
leaf_nodes = [node for node in objgraph.by_type('Node')
358
if not node.children]
359
objgraph.show_backrefs(leaf_nodes[:2], # First 2 leaf nodes
360
filename='leaf_backrefs.png')
361
```
362
363
### Circular Reference Detection
364
365
```python
366
import objgraph
367
368
# Create circular references
369
class CircularA:
370
def __init__(self):
371
self.ref_to_b = None
372
373
class CircularB:
374
def __init__(self):
375
self.ref_to_a = None
376
377
# Create the cycle
378
a = CircularA()
379
b = CircularB()
380
a.ref_to_b = b
381
b.ref_to_a = a
382
383
# Visualize the circular reference
384
objgraph.show_refs([a],
385
max_depth=3,
386
highlight=lambda x: isinstance(x, (CircularA, CircularB)),
387
filename='circular_refs.png')
388
389
# Also show backrefs to see the complete cycle
390
objgraph.show_backrefs([a],
391
max_depth=3,
392
highlight=lambda x: isinstance(x, (CircularA, CircularB)),
393
filename='circular_backrefs.png')
394
```