FlyRanch / figurefirst

A layout-first approach to figure making
http://flyranch.github.io/figurefirst
MIT License
80 stars 15 forks source link

Feature request: Adding arbitrary metadata to figurefirst objects #50

Open clbarnes opened 5 years ago

clbarnes commented 5 years ago

Figures often have data which needs to be given in the caption: it would be nice to keep that data contained with the SVG itself, in a format both machine- and human-readable. As an example, in my plotting code I do some linear regression, whose parameters I would like to save to include in my text.

I saw there was the FigureLayout.save_fifi_data, but that pickles data to a separate file.

The obvious solution is a figurefirst:data XML tag which contains arbitrary XML (namespaced with something like f"figurefirst:data-{user key}", which would be associated with the item it's annotating. That tag could go in the output layer (my only reservation about this is that when the SVG is prepared for publication, it might be nice to be able to strip this data out as easily as deleting the template layer is). There's scope for adding data directly to the template rects from inkscape (as another extension) as default data which is copied across automatically.

I suppose in an ideal world the whole data hierarchy would be XML-serialised, but as a first pass there could just be one tag with a JSON payload in it, as that would play very nicely with python, and is terse, implicitly typed, and fairly human-readable.

I envision a something like this (with some kludges where I don't understand the process of going between FFItem and XML):

class FFDataMixin(object):
    _fifi_data = None
    fifi_encoder = None
    fifi_decoder = None

    @property
    def fifi_data(self):
        if self._fifi_data is None:
            self._fifi_data = get_data_from_xml() or dict()
        return self._fifi_data

    @fifi_data.setter
    def fifi_data(self, value):
        self._fifi_data = value

    def _load_fifi_data(self):
        # do something (using self.fifi_decoder) or if there's no data there:
        return None

    def _dumps_fifi_data(self, **kwargs):
        if not self._fifi_data:
            return ''
        json_kwargs = {"cls": self.fifi_encoder}
        json_kwargs.update(kwargs)
        return "<figurefirst:data>{}</figurefirst:data>".format(json.dumps(self._fifi_data, **json_kwargs))

This could then be subclassed by at least the FFFigure and FFAxis, if not other FFItems.

psilentp commented 4 years ago

Hey sorry not responding and creating a stale issue. I think this is a great idea, @florisvb I think you've been using the save_fifi_data and this dovetails nicely with this -- what are your thoughts? Is mixing JSON and XML together in the same doc going to create some horrendous wolf/vampire hybrid?

Actually, now that I think of it this describes most of the web... so yes, get out the crossbow!

clbarnes commented 4 years ago

I guess this is pretty much us making our own spec, so it could be anything we want. Even if we put it in XML, it wouldn't be part of the SVG spec. But there are other elements of the SVG spec which allow you to stuff raw bytes in (raster images), so we could leave it up to the user - maybe there could be a content-type attribute on the containing tag.

That said, I'm trying to recall exactly what my use case was - I wanted to store numbers associated with the plot (which can be regenerated and changed) so that they can be automatically inserted into e.g. the figure text. But that second parsing step would either need to use figurefirst itself to do the parsing (in which case why not just do it all at once, or the data would have to be exposed as something regex-able inside the SVG which sounds really, really gross.

I think what I ended up doing, for this paper at least (which is still in prep :sweat_smile: ), was that the script which generated the figure using mpl/fifi also generated the TeX figure caption, and then the source document included both. The coupling is still pretty tight but at least the fifi and tex toolchains don't need to interact.

psilentp commented 4 years ago

Good luck on the pape! Do you want to close this, or keep it open for future plans?