Skip to content

Commit 66e9fa2

Browse files
committed
BUG : fix svg corner case
Under certain conditions the ``id`` of the `clipPath` node emitted by the svg writer will be the same for multiple files. If both svg fragments are embedded in the same document, then one of them is removed, the clipping of the remaining fragment can become inconsistent. See ipython/ipython#8133 Closes matplotlib#4349
1 parent c85c67b commit 66e9fa2

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Add salt to cilpPath id
2+
```````````````````````
3+
4+
Add salt to the hash used to determine the id of the ``clipPath``
5+
nodes. This is to avoid conflicts in two svg documents with the same
6+
clip path are included in the same document (see
7+
https://github.com/ipython/ipython/issues/8133 and
8+
https://github.com/matplotlib/matplotlib/issues/4349 ), however this
9+
means that the svg output is no longer deterministic if the same
10+
figure is saved twice. It is not expected that this will affect any
11+
users as the current ids are generated from an md5 hash of properties
12+
of the clip path and any user would have a very difficult time
13+
anticipating the value of the id.

lib/matplotlib/backends/backend_svg.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import numpy as np
1111

1212
from hashlib import md5
13+
import uuid
1314

1415
from matplotlib import verbose, __version__, rcParams
1516
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
@@ -255,7 +256,7 @@ def __init__(self, width, height, svgwriter, basename=None, image_dpi=72):
255256
self.width = width
256257
self.height = height
257258
self.writer = XMLWriter(svgwriter)
258-
self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with
259+
self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with
259260

260261
self._groupd = {}
261262
if not rcParams['svg.image_inline']:
@@ -309,9 +310,14 @@ def _write_default_style(self):
309310

310311
def _make_id(self, type, content):
311312
content = str(content)
313+
salt = str(uuid.uuid4())
312314
if six.PY3:
313315
content = content.encode('utf8')
314-
return '%s%s' % (type, md5(content).hexdigest()[:10])
316+
salt = salt.encode('utf8')
317+
m = md5()
318+
m.update(salt)
319+
m.update(content)
320+
return '%s%s' % (type, m.hexdigest()[:10])
315321

316322
def _make_flip_transform(self, transform):
317323
return (transform +
@@ -532,7 +538,7 @@ def close_group(self, s):
532538

533539
def option_image_nocomposite(self):
534540
"""
535-
return whether to generate a composite image from multiple images on
541+
return whether to generate a composite image from multiple images on
536542
a set of axes
537543
"""
538544
if rcParams['svg.image_noscale']:

0 commit comments

Comments
 (0)