Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 172baa1

Browse files
committed
Move the debug-mode TransformNode.write_graphviz out.
It was only accessible by modifying the source of transforms.py to set DEBUG to True (before the module is imported), and anyways broken because transforms are not hashable in Py3 (so the call to hash() fails). Instead move it to a private module. Example use: ``` from matplotlib._internal_utils import graphviz_dump_transform graphviz_dump_transform(plt.gca().transAxes, "/tmp/test.png") ``` Also, stop tracking transform node children even in debug mode, as it was only used when dumping the transform but that's not even necessary -- one can just inspect `vars(node)` to look for children. Also fix `AffineBase.__eq__` to check that the "other" object has a get_matrix method, to not raise an AttributeError when comparing with Bboxes (which don't).
1 parent b34895d commit 172baa1

File tree

2 files changed

+65
-61
lines changed

2 files changed

+65
-61
lines changed

lib/matplotlib/_internal_utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Internal debugging utilities, that are not expected to be used in the rest of
3+
the codebase.
4+
5+
WARNING: Code in this module may change without prior notice!
6+
"""
7+
8+
from io import StringIO
9+
from pathlib import Path
10+
import subprocess
11+
12+
from matplotlib.transforms import TransformNode
13+
14+
15+
def graphviz_dump_transform(transform, dest, *, highlight=None):
16+
"""
17+
Generate a graphical representation of the transform tree for *transform*
18+
using the :program:`dot` program (which this function depends on). The
19+
output format (png, dot, etc.) is determined from the suffix of *dest*.
20+
21+
Parameters
22+
----------
23+
transform : `~matplotlib.transform.Transform`
24+
The represented transform.
25+
dst : str
26+
Output filename. The extension must be one of the formats supported
27+
by :program:`dot`, e.g. png, svg, dot, ...
28+
(see https://www.graphviz.org/doc/info/output.html).
29+
highlight : list of `~matplotlib.transform.Transform` or None
30+
The transforms in the tree to be drawn in bold.
31+
If *None*, *transform* is highlighted.
32+
"""
33+
34+
if highlight is None:
35+
highlight = [transform]
36+
seen = set()
37+
38+
def recurse(root, buf):
39+
if id(root) in seen:
40+
return
41+
seen.add(id(root))
42+
props = {}
43+
label = type(root).__name__
44+
if root._invalid:
45+
label = f'[{label}]'
46+
if root in highlight:
47+
props['style'] = 'bold'
48+
props['shape'] = 'box'
49+
props['label'] = '"%s"' % label
50+
props = ' '.join(map('{0[0]}={0[1]}'.format, props.items()))
51+
buf.write(f'{id(root)} [{props}];\n')
52+
for key, val in vars(root).items():
53+
if isinstance(val, TransformNode) and id(root) in val._parents:
54+
buf.write(f'"{id(root)}" -> "{id(val)}" '
55+
f'[label="{key}", fontsize=10];\n')
56+
recurse(val, buf)
57+
58+
buf = StringIO()
59+
buf.write('digraph G {\n')
60+
recurse(transform, buf)
61+
buf.write('}\n')
62+
subprocess.run(
63+
['dot', '-T', Path(dest).suffix[1:], '-o', dest],
64+
input=buf.getvalue().encode('utf-8'), check=True)

lib/matplotlib/transforms.py

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,6 @@ def set_children(self, *children):
178178
target=child._parents: target.pop(sid))
179179
child._parents[id(self)] = ref
180180

181-
if DEBUG:
182-
_set_children = set_children
183-
184-
def set_children(self, *children):
185-
self._set_children(*children)
186-
self._children = children
187-
set_children.__doc__ = _set_children.__doc__
188-
189181
def frozen(self):
190182
"""
191183
Returns a frozen copy of this transform node. The frozen copy
@@ -195,58 +187,6 @@ def frozen(self):
195187
"""
196188
return self
197189

198-
if DEBUG:
199-
def write_graphviz(self, fobj, highlight=[]):
200-
"""
201-
For debugging purposes.
202-
203-
Writes the transform tree rooted at 'self' to a graphviz "dot"
204-
format file. This file can be run through the "dot" utility
205-
to produce a graph of the transform tree.
206-
207-
Affine transforms are marked in blue. Bounding boxes are
208-
marked in yellow.
209-
210-
*fobj*: A Python file-like object
211-
212-
Once the "dot" file has been created, it can be turned into a
213-
png easily with::
214-
215-
$> dot -Tpng -o $OUTPUT_FILE $DOT_FILE
216-
217-
"""
218-
seen = set()
219-
220-
def recurse(root):
221-
if root in seen:
222-
return
223-
seen.add(root)
224-
props = {}
225-
label = root.__class__.__name__
226-
if root._invalid:
227-
label = '[%s]' % label
228-
if root in highlight:
229-
props['style'] = 'bold'
230-
props['shape'] = 'box'
231-
props['label'] = '"%s"' % label
232-
props = ' '.join(map('{0[0]}={0[1]}'.format, props.items()))
233-
234-
fobj.write('%s [%s];\n' % (hash(root), props))
235-
236-
if hasattr(root, '_children'):
237-
for child in root._children:
238-
name = next((key for key, val in root.__dict__.items()
239-
if val is child), '?')
240-
fobj.write('"%s" -> "%s" [label="%s", fontsize=10];\n'
241-
% (hash(root),
242-
hash(child),
243-
name))
244-
recurse(child)
245-
246-
fobj.write("digraph G {\n")
247-
recurse(self)
248-
fobj.write("}\n")
249-
250190

251191
class BboxBase(TransformNode):
252192
"""
@@ -1670,7 +1610,7 @@ def __array__(self, *args, **kwargs):
16701610
return self.get_matrix()
16711611

16721612
def __eq__(self, other):
1673-
if getattr(other, "is_affine", False):
1613+
if getattr(other, "is_affine", False) and hasattr(other, "get_matrix"):
16741614
return np.all(self.get_matrix() == other.get_matrix())
16751615
return NotImplemented
16761616

0 commit comments

Comments
 (0)