Skip to content

matplotlib.colors rgb2hex is not the right inverse of hex2color #18574

Closed

Description

@SebastianoF
>>> matplotlib.__version__
'3.3.2'
>>> from matplotlib.colors import rgb2hex, hex2color
>>> rgb_color = (0.5, 0.5, 0.9)
>>> hex2color(rgb2hex(rgb_color))
(0.5019607843137255, 0.5019607843137255, 0.9019607843137255)

It should return (0.5, 0.5, 0.9).
As it seems the additive factor it is always the same, it should be a matter of subtracting 0.0019607843137255 from the three channels.

Thanks!


P.S. the inverse composition works as expected:

>>> rgb2hex(hex2color( '#808080'))
'#808080'

Activity

  1. changed the title [-]matplotlib.colors rgb2hex and hex2color are not bijective.[/-] [+]matplotlib.colors rgb2hex is not the right inverse of hex2color[/+] on Sep 25, 2020
  2. SebastianoF commented on Sep 25, 2020

    @SebastianoF
    Author

    (Also renaming hex2color to hex2rgb for a next major release would simplify the interface)

  3. jklymak commented on Sep 25, 2020

    @jklymak
    Member

    What happens if you run that through twice? Does the error accumulate or is it steady?

  4. tacaswell commented on Sep 25, 2020

    @tacaswell
    Member

    It is stable after the first round-trip:

    In [214]: rgb_color = (0.5, 0.5, 0.9)
    
    In [215]: rt = lambda c: hex2color(rgb2hex(c))
    
    In [216]: rt(rgb_color)
    Out[216]: (0.5019607843137255, 0.5019607843137255, 0.9019607843137255)
    
    In [217]: rt(rt(rgb_color))
    Out[217]: (0.5019607843137255, 0.5019607843137255, 0.9019607843137255)
    
    In [218]: rt(rt(rt(rgb_color)))
    Out[218]: (0.5019607843137255, 0.5019607843137255, 0.9019607843137255)
    
    In [219]: 
    

    I think that this is unavoidable because in hex we only have 256 possible values where as floats we have many more (in theory infinite, in practice "a lot" due to the limitations of floating point). Hence, when we go from float -> hex many float values will convert to the same hex value, but when we go back to float we can only map to one value, thus we get the miss-match when we try to round-trip.

    If you start from hex you are mapping one integer value into the reals and then mapping 1 float value back to int so it is invertable.


    In #6382 we added more consistently named functions (see https://matplotlib.org/api/colors_api.html#functions) but did not remove the old ones because we did not think that the possibility of breaking users code was worth the simplification.


    I am going to close this issue as there is nothing we can do about float -> int -> float round tripping being lossey and we already have clearer names available.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions