Skip to content

change IGroup __repr__ #447

Description

@gdementen

If we want to return IGroup instead of LGroup for stuff like Axis/Group.startingwith,endingwith,... (see #438) we need to change IGroup __repr__ to somehow display the label the position corresponds to. Otherwise it makes it harder than necessary to debug any code using them. The problem is that I haven't found a way to add this without breaking the eval(repr(v)) == v which is unfortunate.

>>> a = Axis('a=a0..a5')
>>> # current situation
>>> a["a1,a3,a4"]
a['a1', 'a3', 'a4']
>>> a.i[1, 3, 4]
a.i[1, 3, 4]
>>> # alternative 1
>>> a.i[1, 3, 4]
a.i['a1' (1), 'a3' (3), 'a4' (4)]
>>> # alternative 2 -- this is more "pure" but looks less pretty
>>> a.i[1, 3, 4]
a.i[1 ('a1'), 3 ('a3'), 4 ('a4')]
>>> # alternative 3
>>> a.i[1, 3, 4]
a.i[1, 3, 4 ('a1', 'a3', 'a4')]
>>> # alternative 4
>>> a.i[1, 3, 4]
a.i[1, 3, 4] ('a1', 'a3', 'a4')
>>> # alternative 5 -- this is even more "pure" (we could make it evaluate correctly) but looks even less pretty
>>> a.i[1, 3, 4]
IGroup([1, 3, 4], axis=a, display=['a1', 'a3', 'a4'])

There are potentially many other alternatives. Please suggest them if you have any idea.

Two special problems

  • positional slices, for which the stop bound is not inclusive, which means that slices ending at the end of the axis are problematic (and other slices are unintuitive)
>>> a.i[1:6]
a.i[1 ('a1'): 6 (??)]
>>> # having 'a3' displayed (but not included) makes it more confusing
>>> a.i[1:3]
a.i[1 ('a1'): 3 ('a3')]
>>> # maybe doing a special case for slices would make sense (ie do not translate each bound separately but the whole "key":
>>> a.i[1:3]
a.i[1:3 ('a1':'a2')]
  • slices on axes with integer labels (especially if pos == label) are a bit confusing (but they are probably already confusing even though the confusion is hidden ;-)).
>>> a = Axis('a=0..10')
>>> # current
>>> a.i[1:3]
a.i[1:3]
>>> # each bound separately
>>> a.i[1:3]
a.i[1 (1): 3 (3)]
>>> # the whole key
>>> a.i[1:3]
a.i[1:3 (1:2)]

My current preference goes for alternative 4 (because it will be easier to copy-paste than alternative 3) and for slices, to translate the whole key instead of each bound separately.

Activity

  1. gdementen commented on Sep 25, 2017

    @gdementen
    ContributorAuthor

    Here is a concrete example when you would get an IGroup without explicitly asking for it:

    >>> people = Axis(['Bruce Wayne', 'Bruce Willis', 'Arthur Dent'], 'people')
    >>> group = people.startingwith('Bru')
    >>> # current
    >>> group
    people['Bruce Wayne', 'Bruce Willis']
    >>> # alternative 4
    >>> group
    people.i[0, 1] ('Bruce Wayne', 'Bruce Willis')
    >>> # current
    >>> group.containing('Will')
    people['Bruce Willis']
    >>> # alternative 4
    >>> group.containing('Will')
    people.i[1] ('Bruce Willis')
  2. gdementen commented on Sep 25, 2017

    @gdementen
    ContributorAuthor

    Yet another option is to blur the difference between IGroup and LGroup and only display the position in the presence of duplicate labels:

    >>> people = Axis(['Bruce', 'Bruce', 'Bru'], 'people')
    >>> group = people.startingwith('Bru')
    >>> # current (which is broken and select the first or last 'Bruce' twice)
    >>> group
    people['Bruce', 'Bruce', 'Bru']
    >>> # alternative 4
    >>> group
    people.i[0, 1, 2] ('Bruce', 'Bruce', 'Bru')
    >>> # alternative 6. It is the nicest of all IMO but breaks eval(repr) badly 
    >>> # when there is no duplicate, it is indistinguishable from an LGroup (which is both
    >>> # a bad and a good thing)
    >>> group
    people['Bruce' (0), 'Bruce' (1), 'Bru']
    >>> people.i[1, 2]
    people['Bruce' (1), 'Bru']
  3. alixdamman commented on Sep 25, 2017

    @alixdamman
    Collaborator

    My first choice is also alternative 4 (which, indeed, allows easy copy/paste) and to translate the whole key instead of each bound separately for slices.

    I wouldn't "blur" the difference between PGroup and LGroup. It's good to know when you are dealing with PGroup or LGroup. Explicit is better than implicit.

  4. added this to the 0.30 milestone on Feb 12, 2018
  5. modified the milestones: 0.30, 0.31 on Jul 18, 2018
  6. changed the title [-]change PGroup __repr__[/-] [+]change IGroup __repr__[/+] on Jun 24, 2019
  7. removed this from the 0.31 milestone on Aug 1, 2019
  8. gdementen commented on Mar 31, 2026

    @gdementen
    ContributorAuthor

    I wonder if it wouldn't be simpler to just ensure we have no duplicate label on Axis construction (it would incur a performance penalty but I assume it would be very small -- or even negligible in our models I think) by deduplicating them:

    Something like:

    >>> Axis('test=a,a,a,a')
    Axis(['a#0', 'a#1', 'a#2', 'a#3'], 'a')

    or maybe start counting at 1??? Unsure what would be least confusing. See what Pandas does for columns.

    Then we can always use IGroups (except for X.) but display them like LGroups

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions