oemof / oemof-solph

A model generator for energy system modelling and optimisation (LP/MILP).
https://oemof.org
MIT License
301 stars 126 forks source link

Adding tags to components #557

Open henhuy opened 5 years ago

henhuy commented 5 years ago

I would find it very helpful to add an attribute tags of type list or tuple to oemof.network.Node holding strings for filtering results later!

It was suggested to add such thing to attribute label (as collections.namedtuple for example), but this leads to great disadvantage for me: When processing results with keys converted to str, my namedtuples-labels are processed as:

>>> from collections import namedtuple
>>> a = namedtuple('AdvancedLabel', ['name', 'tags'])
>>> b = a('bus', ('tag_one', 'tag_two'))
>>> b
AdvancedLabel(name='bus', tags=('tag_one', 'tag_two'))

Leading to node results as:

{
    'scalars': {
        'label': 'AdvancedLabel(name='bus', tags=('tag_one', 'tag_two'))'
        ...
    },
    'sequences': ...
}

Then, filtering results leads to ugly str-splitting/regex/whatever operations.

In my opinion, it would be nicer to have them separated, so that node results lead to something like:

{
    'scalars': {
        'label': 'bus', 
        ...
    },
    'sequences': {
        'tags': ('tag_one', 'tag_two'},
        ...
    }
}

What do you think?

uvchik commented 5 years ago

I use namedtuples as labels and do NOT convert them to strings. Doing so it is very easy to filter nodes.

You can find some explanations in this posting or in this example.

If you really want to use strings instead of the namedtuple you can define your own string representation.

class Label(namedtuple('solph_label', ['tag1', 'tag2', 'tag3'])):
    __slots__ = ()

    def __str__(self):
        """The string is used within solph as an ID, so it hast to be unique"""
        return '_'.join(map(str, self._asdict().values()))

Instead of the underscore you could use a special character which makes it easy to split afterwards.

uvchik commented 5 years ago

If you really want to use strings you can use a string or a normal tuple:

>>> label = "tag_1§tag2§tag3"
>>> label.split('§')
['tag_1', 'tag2', 'tag3']

>>> label = tuple(['tag_1', 'tag_2', 'tag_3'])
>>> label
('tag_1', 'tag_2', 'tag_3')
henhuy commented 5 years ago

I have to use strings because I store and restore results from database. And that was the easiest solution.

Your suggestions work of course. I implemented a similar workaround to handle it for myself.

But my idea was to implement a more common/user-friendly approach. Having a new "standard" of tagging components, it would also be nice to add standard filtering functions to processing module.

I think this could be implemented easily and would be appreciated by our users.