Hello,
I often embed figures as SVG graphics in web pages. As part of this
process, I usually do the following
1.
Set gids on artists and link that gid to a set of data describing that
part of a graphic in an external dictionary. This includes things like
setting the element?s class, extra contextual information, information that
would be good to show in a tooltip, ids of related elements, and so forth.
2.
Serialize the figure into a file-like object, use an element tree
implementation?s XMLID to get an element id map and Element objects
3.
Iterate over my data dictionary from (1) and set keys in the mapped
Element?s attrib dictionary, using the id map from (2)
4.
Use the element tree implementation?s tostring function to serialize the
updated Element objects back into a string and then send the string out as
a response to a web request.
5.
After receiving the SVG string from the server on the client, add the
SVG to the page?s DOM and then hang event handlers on it (or pre-specify
delegated handlers) that use the added attributes to configure interactive
behavior.
I looked at the Artist type and saw no good place to store ?arbitrary
data?. Before I start working on this I wanted to know if anyone else had a
better solution. I would also like to know if the devs would be opposed to
a PR that adds an extra dictionary/attribute to every Artist instance
created.
Another alternative solution would be to find a way to push my dictionary
mapping gids to extra attributes into the SVGRenderer and have it pass them
as **extras to XMLWriter.element when it processes individual artists.
Here?s a generic example of what I do currently:
def plot_with_extras_for_svg(*data, **kwargs):
# Do the plotting, generating the id-linked data in `id_mapper`
ax, id_mapper = plot_my_data(*data, **kwargs)
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# compute the total space used in both dimensions when dealing with
# negative axis bounds
x_size = sum(map(abs, xlim))
y_size = sum(map(abs, ylim))
# Map the used axis space to the drawable region dimensions
aspect_ratio = x_size / y_size
canvas_x = 8.
canvas_y = canvas_x / aspect_ratio
# Configure the artist to draw within the new drawable region bounds
fig = ax.get_figure()
fig.tight_layout(pad=0.2)
fig.patch.set_visible(False)
fig.set_figwidth(canvas_x)
fig.set_figheight(canvas_y)
ax.patch.set_visible(False)
# Perform the first serialization
buff = StringIO()
fig.savefig(buff, format='svg')
# Parse XML buffer from `buff` and configure tag attributes
root, ids = ET.XMLID(buff.getvalue())
root.attrib['class'] = 'plot-class-svg'
for id, attributes in id_mapper.items():
element = ids[id]
element.attrib.update({("data-" + k): str(v)
for k, v in attributes.items()})
element.attrib['class'] = id.rsplit('-')[0]
# More drawable space shenanigans
min_x, min_y, max_x, max_y = map(int, root.attrib["viewBox"].split(" "))
min_x += 100
max_x += 200
view_box = ' '.join(map(str, (min_x, min_y, max_x, max_y)))
root.attrib["viewBox"] = view_box
width = float(root.attrib["width"][:-2]) * 1.75
root.attrib["width"] = "100%"
height = width / (aspect_ratio)
root.attrib["height"] = "%dpt" % (height * 1.2)
root.attrib["preserveAspectRatio"] = "xMinYMin meet"
# Second serialization
svg = ET.tostring(root)
plt.close(fig)
return svg
Thank you
?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20170322/a9aeefda/attachment-0001.html>