Skip to content

Pass gid to renderer #15087

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/api/next_api_changes/2019-08-19-pass_gid.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
The ``gid`` is now correctly passed to svg output
`````````````````````````````````````````````````

Previously, if a figure, axis, legend or some other artists had a custom
``gid`` set (e.g. via ``.set_gid()``), this would not be reflected in
the svg output. Instead a default gid, like ``figure_1`` would be shown.
This is now fixed, such that e.g. ``fig.set_gid("myfigure")`` correctly
shows up as ``<g id="myfigure">`` in the svg file. If you relied on the
gid having the default format, you now need to make sure not to set the
``gid`` parameter of the artists.
2 changes: 1 addition & 1 deletion lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2560,7 +2560,7 @@ def draw(self, renderer=None, inframe=False):
return
self._unstale_viewLim()

renderer.open_group('axes')
renderer.open_group('axes', gid=self.get_gid())

# prevent triggering call backs during the draw process
self._stale = True
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def draw(self, renderer):
if not self.get_visible():
self.stale = False
return
renderer.open_group(self.__name__)
renderer.open_group(self.__name__, gid=self.get_gid())
for artist in [self.gridline, self.tick1line, self.tick2line,
self.label1, self.label2]:
artist.draw(renderer)
Expand Down Expand Up @@ -1222,7 +1222,7 @@ def draw(self, renderer, *args, **kwargs):

if not self.get_visible():
return
renderer.open_group(__name__)
renderer.open_group(__name__, gid=self.get_gid())

ticks_to_draw = self._update_ticks()
ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw,
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -1882,7 +1882,7 @@ def convert_mesh_to_paths(tri):
def draw(self, renderer):
if not self.get_visible():
return
renderer.open_group(self.__class__.__name__)
renderer.open_group(self.__class__.__name__, gid=self.get_gid())
transform = self.get_transform()

# Get a list of triangles and the color at each vertex.
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1724,7 +1724,7 @@ def draw(self, renderer):
child.apply_aspect()

try:
renderer.open_group('figure')
renderer.open_group('figure', gid=self.get_gid())
if self.get_constrained_layout() and self.axes:
self.execute_constrained_layout(renderer)
if self.get_tight_layout() and self.axes:
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ def draw(self, renderer):
if not self.get_visible():
return

renderer.open_group('legend')
renderer.open_group('legend', gid=self.get_gid())

fontsize = renderer.points_to_pixels(self._fontsize)

Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ def draw(self, renderer):

if not self.get_visible():
return
renderer.open_group('table')
renderer.open_group('table', gid=self.get_gid())
self._update_positions(renderer)

for key in sorted(self._cells):
Expand Down
65 changes: 64 additions & 1 deletion lib/matplotlib/tests/test_backend_svg.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import numpy as np
from io import BytesIO
import os
import re
import tempfile
import warnings
Expand Down Expand Up @@ -145,3 +144,67 @@ def test_svgnone_with_data_coordinates():
buf = fd.read().decode()

assert expected in buf


def test_gid():
"""Test that object gid appears in output svg."""
from matplotlib.offsetbox import OffsetBox
from matplotlib.axis import Tick

fig = plt.figure()

ax1 = fig.add_subplot(131)
ax1.imshow([[1., 2.], [2., 3.]], aspect="auto")
ax1.scatter([1, 2, 3], [1, 2, 3], label="myscatter")
ax1.plot([2, 3, 1], label="myplot")
ax1.legend()
ax1a = ax1.twinx()
ax1a.bar([1, 2, 3], [1, 2, 3])

ax2 = fig.add_subplot(132, projection="polar")
ax2.plot([0, 1.5, 3], [1, 2, 3])

ax3 = fig.add_subplot(133, projection="3d")
ax3.plot([1, 2], [1, 2], [1, 2])

fig.canvas.draw()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the draw() here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't draw it, the ticks will not be the ones that are exported, because the ticker only creates them when drawing the figure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, of course.


gdic = {}
for idx, obj in enumerate(fig.findobj(include_self=True)):
if obj.get_visible():
gid = f"test123{obj.__class__.__name__}_{idx}"
gdic[gid] = obj
obj.set_gid(gid)

fd = BytesIO()
fig.savefig(fd, format='svg')
fd.seek(0)
buf = fd.read().decode()
fd.close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could just write:

with BytesIO() as fd:
    fig.savefig(...)
    buf = fd.getvalue()  # no need to seek() :)


def include(gid, obj):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps has_gid() or gid_is_set() (it's not totally clear what "include" means here)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really literally, whether or not to include an object in the test. (Not all objects in the figure actually appear in the svg, so we need to exclude them). I've added a docstring to it.

# we need to exclude certain objects which will not appear in the svg
if isinstance(obj, OffsetBox):
return False
if isinstance(obj, plt.Text):
if obj.get_text() == "":
return False
elif obj.axes is None:
return False
if isinstance(obj, plt.Line2D):
if np.array(obj.get_data()).shape == (2, 1):
return False
elif not hasattr(obj, "axes") or obj.axes is None:
return False
if isinstance(obj, Tick):
loc = obj.get_loc()
if loc == 0:
return False
vi = obj.get_view_interval()
if loc < min(vi) or loc > max(vi):
return False
return True

for gid, obj in gdic.items():
if include(gid, obj):
assert gid in buf
4 changes: 2 additions & 2 deletions lib/mpl_toolkits/axisartist/axis_artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def draw(self, renderer):

if not self._visible:
return
renderer.open_group('line2d')
renderer.open_group('line2d', gid=self.get_gid())

gc = renderer.new_gc()
self._set_gc_clip(gc)
Expand Down Expand Up @@ -1230,7 +1230,7 @@ def draw(self, renderer):
if not self.get_visible():
return

renderer.open_group(__name__)
renderer.open_group(__name__, gid=self.get_gid())

self._axis_artist_helper.update_lim(self.axes)

Expand Down
4 changes: 2 additions & 2 deletions lib/mpl_toolkits/mplot3d/axis3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def _get_coord_info(self, renderer):
return mins, maxs, centers, deltas, tc, highs

def draw_pane(self, renderer):
renderer.open_group('pane3d')
renderer.open_group('pane3d', gid=self.get_gid())

mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)

Expand All @@ -209,7 +209,7 @@ def draw_pane(self, renderer):
@artist.allow_rasterization
def draw(self, renderer):
self.label._transform = self.axes.transData
renderer.open_group('axis3d')
renderer.open_group('axis3d', gid=self.get_gid())

ticks = self._update_ticks()

Expand Down