Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
SebastianoF opened this issue Sep 25, 2020 · 3 comments
Closed

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

SebastianoF opened this issue Sep 25, 2020 · 3 comments

Comments

@SebastianoF
Copy link

SebastianoF commented Sep 25, 2020

>>> 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'
@SebastianoF SebastianoF changed the title matplotlib.colors rgb2hex and hex2color are not bijective. matplotlib.colors rgb2hex is not the right inverse of hex2color Sep 25, 2020
@SebastianoF
Copy link
Author

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

@jklymak
Copy link
Member

jklymak commented Sep 25, 2020

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

@tacaswell
Copy link
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants