diff --git a/doc/api/api_changes/2015-04-27_svgclip_url.rst b/doc/api/api_changes/2015-04-27_svgclip_url.rst new file mode 100644 index 000000000000..5572fb388c76 --- /dev/null +++ b/doc/api/api_changes/2015-04-27_svgclip_url.rst @@ -0,0 +1,13 @@ +Add salt to cilpPath id +``````````````````````` + +Add salt to the hash used to determine the id of the ``clipPath`` +nodes. This is to avoid conflicts in two svg documents with the same +clip path are included in the same document (see +https://github.com/ipython/ipython/issues/8133 and +https://github.com/matplotlib/matplotlib/issues/4349 ), however this +means that the svg output is no longer deterministic if the same +figure is saved twice. It is not expected that this will affect any +users as the current ids are generated from an md5 hash of properties +of the clip path and any user would have a very difficult time +anticipating the value of the id. diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 4462c9b12cf6..5c58345e6fba 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -10,6 +10,7 @@ import numpy as np from hashlib import md5 +import uuid from matplotlib import verbose, __version__, rcParams from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ @@ -255,7 +256,7 @@ def __init__(self, width, height, svgwriter, basename=None, image_dpi=72): self.width = width self.height = height self.writer = XMLWriter(svgwriter) - self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with + self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with self._groupd = {} if not rcParams['svg.image_inline']: @@ -309,9 +310,14 @@ def _write_default_style(self): def _make_id(self, type, content): content = str(content) + salt = str(uuid.uuid4()) if six.PY3: content = content.encode('utf8') - return '%s%s' % (type, md5(content).hexdigest()[:10]) + salt = salt.encode('utf8') + m = md5() + m.update(salt) + m.update(content) + return '%s%s' % (type, m.hexdigest()[:10]) def _make_flip_transform(self, transform): return (transform + @@ -532,7 +538,7 @@ def close_group(self, s): def option_image_nocomposite(self): """ - return whether to generate a composite image from multiple images on + return whether to generate a composite image from multiple images on a set of axes """ if rcParams['svg.image_noscale']: