1

I'm trying to make a simple object called Color. I want this to have the same functionality as a string encoded as a hex color. It looks like it's working but doesn't have the same capabilities.

Edit: In response to the accepted answer below:

import pandas as pd
from matplotlib.colors import to_rgb, rgb2hex


class Color(str):
    def __new__(cls, value, *args, **kwargs):
        # explicitly only pass value to the str constructor
        cls.color = rgb2hex(to_rgb(value))
        return super(Color, cls).__new__(cls, cls.color)

x = pd.Series([Color("fuchsia"), Color("black")])
print(x)
# 0    #ff00ff
# 1    #000000
# dtype: object
print("Should be fuchsia but it's black", x[0].color)
# Should be fuchsia but it's black #000000
print("Should be black", x[0].color)
# Should be black #000000

Original:

For example, the following operations work:

print(color)
print(pd.Series(color))
print(to_rgb(str(color)))

but this does not:

print(to_rgb(color))

I can't figure out why this isn't working. I've tried this but it doesn't fit the case: Python, represent non-string object as string?

from matplotlib.colors import hex2color, to_rgb, to_rgba


class Color(object):
    # Built in
    def __init__(self, color):
        self.color = rgb2hex(to_rgb(color))
    def __repr__(self):
        return self.color
    def __str__(self):
        return self.color

color = Color("black")
print(color)
# #000000
print(pd.Series(color))
# 0    #000000
# dtype: object
print(to_rgb(str(color)))
# (0.0, 0.0, 0.0)
print(to_rgb(color))

Here is the error:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/anaconda/envs/µ_env/lib/python3.6/site-packages/matplotlib/colors.py in to_rgba(c, alpha)
    173     try:
--> 174         rgba = _colors_full_map.cache[c, alpha]
    175     except (KeyError, TypeError):  # Not in cache, or unhashable.

KeyError: (#000000, None)

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-35-a478f942e1d2> in <module>
     16 print(pd.Series(color))
     17 print(to_rgb(str(color)))
---> 18 print(to_rgb(color))

~/anaconda/envs/µ_env/lib/python3.6/site-packages/matplotlib/colors.py in to_rgb(c)
    279 def to_rgb(c):
    280     """Convert *c* to an RGB color, silently dropping the alpha channel."""
--> 281     return to_rgba(c)[:3]
    282 
    283 

~/anaconda/envs/µ_env/lib/python3.6/site-packages/matplotlib/colors.py in to_rgba(c, alpha)
    174         rgba = _colors_full_map.cache[c, alpha]
    175     except (KeyError, TypeError):  # Not in cache, or unhashable.
--> 176         rgba = _to_rgba_no_colorcycle(c, alpha)
    177         try:
    178             _colors_full_map.cache[c, alpha] = rgba

~/anaconda/envs/µ_env/lib/python3.6/site-packages/matplotlib/colors.py in _to_rgba_no_colorcycle(c, alpha)
    225         # float)` and `np.array(...).astype(float)` all convert "0.5" to 0.5.
    226         # Test dimensionality to reject single floats.
--> 227         raise ValueError("Invalid RGBA argument: {!r}".format(orig_c))
    228     # Return a tuple to prevent the cached value from being modified.
    229     c = tuple(c.astype(float))

ValueError: Invalid RGBA argument: #000000
6
  • You're supposed to actually show us the output if you have some print calls in your code... Also, what's this rgb2hex? That's the only part of the code we need to explain the puzzle. xD Commented Jul 10, 2019 at 23:25
  • Because your object isn't a string. Commented Jul 10, 2019 at 23:25
  • @ipaleka sorry about that! Totally forgot to include the output. Commented Jul 10, 2019 at 23:29
  • 1
    As @juanpa.arrivillaga said, __repr__ and __str__ should return string. Commented Jul 10, 2019 at 23:46
  • That's not the issue, as far as I can tell they do. The issue is that function expects a string, i.e. to_rgb Commented Jul 10, 2019 at 23:56

1 Answer 1

2

Maybe you want to subclass str to provide your string.

import pandas as pd
from matplotlib.colors import to_rgb, rgb2hex


class Color(str):
    def __new__(cls, value, *args, **kwargs):
        # explicitly only pass value to the str constructor
        v = rgb2hex(to_rgb(value))
        return super(Color, cls).__new__(cls, v)


color = Color("fuchsia")

print(color)
print(pd.Series(color))
print(to_rgb(str(color)))
print(to_rgb(color))

outputs

#ff00ff
0    #ff00ff
dtype: object
(1.0, 0.0, 1.0)
(1.0, 0.0, 1.0)

If you want to store the initial value inside your string, you could do so

class Color(str):
    def __new__(cls, value, *args, **kwargs):
        # explicitly only pass value to the str constructor
        v = rgb2hex(to_rgb(value))
        return super(Color, cls).__new__(cls, v)

    def __init__(self, value):
        self.color = value
Sign up to request clarification or add additional context in comments.

2 Comments

I've noticed something weird when more than one is instantiated. I've added it into the original question
str is immutable. So what you did in the code is to change the color attribute of just every instace of Color. I updated the answer with what I think you want to do. (Also please make sure that the question makes some sense for future readers, who would usually read from top to bottom, not vice versa.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.