Skip to content

Commit cf25ca5

Browse files
committed
FIX: URL links in SVG should have target='_blank'
When embedding SVG in HTML, link `href`s can target different browsing contexts. This e.g. leads to links inside SVGs in matplotlib#31497 replacing the SVG image instead of opening a new browser window. The solution is to set `target="_blank"` for all links that implement `Artist.get_url()`. This is always intended as an external link, so universally adding `target="_blank"` is justified. Background info: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target#_blank
1 parent 05b9179 commit cf25ca5

3 files changed

Lines changed: 16 additions & 6 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
SVG links open in new tab or window
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
`.Artist.set_url` allows to turn the Artist into a link. In SVG output,
4+
this has been implemented without specifying a `target`_ attribute. The default
5+
target value "_self" resulted in replacing the SVG document with the linked page
6+
when the link was clicked.
7+
8+
The target is now set to "_blank" so that the link opens in a new tab or window.
9+
10+
.. _target: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target

lib/matplotlib/backends/backend_svg.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
697697
sketch=gc.get_sketch_params())
698698

699699
if gc.get_url() is not None:
700-
self.writer.start('a', {'xlink:href': gc.get_url()})
700+
self.writer.start('a', {'xlink:href': gc.get_url(), 'target': '_blank'})
701701
self.writer.element('path', d=path_data, **self._get_clip_attrs(gc),
702702
style=self._get_style(gc, rgbFace))
703703
if gc.get_url() is not None:
@@ -730,7 +730,7 @@ def draw_markers(
730730

731731
writer.start('g', **self._get_clip_attrs(gc))
732732
if gc.get_url() is not None:
733-
self.writer.start('a', {'xlink:href': gc.get_url()})
733+
self.writer.start('a', {'xlink:href': gc.get_url(), 'target': '_blank'})
734734
trans_and_flip = self._make_flip_transform(trans)
735735
attrib = {'xlink:href': f'#{oid}'}
736736
clip = (0, 0, self.width*72, self.height*72)
@@ -788,7 +788,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
788788
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
789789
url = gc0.get_url()
790790
if url is not None:
791-
writer.start('a', attrib={'xlink:href': url})
791+
writer.start('a', attrib={'xlink:href': url, 'target': '_blank'})
792792
clip_attrs = self._get_clip_attrs(gc0)
793793
if clip_attrs:
794794
writer.start('g', **clip_attrs)
@@ -966,7 +966,7 @@ def draw_image(self, gc, x, y, im, transform=None):
966966

967967
url = gc.get_url()
968968
if url is not None:
969-
self.writer.start('a', attrib={'xlink:href': url})
969+
self.writer.start('a', attrib={'xlink:href': url, 'target': '_blank'})
970970

971971
attrib = {}
972972
oid = gc.get_gid()
@@ -1288,7 +1288,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
12881288
self.writer.start('g', **clip_attrs)
12891289

12901290
if gc.get_url() is not None:
1291-
self.writer.start('a', {'xlink:href': gc.get_url()})
1291+
self.writer.start('a', {'xlink:href': gc.get_url(), 'target': '_blank'})
12921292

12931293
if mpl.rcParams['svg.fonttype'] == 'path':
12941294
self._draw_text_as_path(gc, x, y, s, prop, angle, ismath, mtext)

lib/matplotlib/tests/test_backend_svg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def test_text_urls():
6565
fig.savefig(fd, format='svg')
6666
buf = fd.getvalue().decode()
6767

68-
expected = f'<a xlink:href="{test_url}">'
68+
expected = f'<a xlink:href="{test_url}" target="_blank">'
6969
assert expected in buf
7070

7171

0 commit comments

Comments
 (0)