[Matplotlib-users] Arbitrary artist data on SVG elements
Thomas Caswell
tcaswell at gmail.com
Sat Apr 1 16:30:30 EDT 2017
Joshua,
That is an interesting use case!
I am hesitant to add this attribute to Artist because it is very specific
to the SVG backend (none of the other backends would make use of this as
far as I know). On the other hand, a generic way to use gid to add extra
information in the SVG backend could be interesting. I am pretty sure
there are examples of optianal backend-specific kwargs going into
`savefig`, what would the API for that look like?
Tom
On Wed, Mar 22, 2017 at 4:42 PM Joshua Klein <mobiusklein at gmail.com> wrote:
> 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
>
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20170401/2d693775/attachment-0001.html>
More information about the Matplotlib-users
mailing list