Skip to content
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

Implement a _repr_html_ method for the Color class #429

Closed
apcamargo opened this issue Aug 11, 2024 · 13 comments · Fixed by #430
Closed

Implement a _repr_html_ method for the Color class #429

apcamargo opened this issue Aug 11, 2024 · 13 comments · Fixed by #430
Labels
S: triage Issue needs triage.

Comments

@apcamargo
Copy link

When working with colors in a Jupyter notebook (or Quarto), it can be helpful to visualize the colors directly. While there are several ways to do this, having this functionality built into coloraid via a _repr_html_ method would be very convenient.

Although this feature might fall outside the intended scope of the library, here’s a quick example I wrote:

def _repr_html_(self) -> str:
    """
    Returns an HTML representation of the color as a colored square,
    with the color's string representation displayed underneath.
    """
    c = self.convert("oklch").to_string()
    return f"""
    <div style="text-align: center;">
        <div style="width: 50px; height: 50px; background-color: {c}; margin: 0 auto;"></div>
        <div>{self.to_string()}</div>
    </div>
    """
image

This is just a quick implementation, and I’m sure there are a number of ways it could be improved.

@gir-bot gir-bot added the S: triage Issue needs triage. label Aug 11, 2024
@facelessuser
Copy link
Owner

It's an interesting idea. It definitely has limited use cases, but I can see it being useful in Jupyter. So Jupyter specifically uses __repr_html__ visualize an object?

@facelessuser
Copy link
Owner

I guess you'd run into the issue of what gamut do we format the colors in...you'd need some class option to output in display-p3 if your monitor supports it. I guess sRGB would be the safe default.

@apcamargo
Copy link
Author

apcamargo commented Aug 11, 2024

I converted the color to OKLCH because, as far as I know, the browser takes care of converting it to a color that the monitor can display.

Regarding _repr_html_, IPython has a number of methods for rich display: https://ipython.readthedocs.io/en/stable/config/integrating.html#rich-display

@facelessuser
Copy link
Owner

Yeah, you could let the browser gamut map out itself. Currently most just clip though which isn't great.

@apcamargo
Copy link
Author

@facelessuser
Copy link
Owner

Thanks for the example. Yeah, it's not a bad idea, and it doesn't hurt us to have it. Let me play around with it.

@facelessuser
Copy link
Owner

Something like this might work. We turn off gamut mapping for string output by default at let the browser do whatever it does. You can obviously gamut map it before output if you want, but this will preserve the current color values for text output as well.

It also has a background for when colors are transparent and a border when color is too similar to background on which the color is displayed on.

from coloraide import Color as Base
from IPython.display import display

class Color(Base):
    def _repr_html_(self) -> str:
        """
        Returns an HTML representation of the color as a colored square,
        with the color's string representation displayed underneath.
        """
        c = self.convert("oklab").to_string()
        return f"""
        <div style="text-align: center;">
            <div style="width: 52px; height: 52px; background: url(&quot;data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill-opacity='0.1'><rect width='50' height='50' /><rect x='50' y='50' width='50' height='50' /></svg>&quot;)
  0 0 / 0.5em 0.5em #fefefe; margin: 0 auto;"><div style="width: 50px; height: 50px; background-color: {c}; border: 2px ridge hsl(0, 0%, 85%);"></div></div>
            <div>{self.to_string(fit=False)}</div>
        </div>
        """

display(Color('color(srgb 1 0 0 / 0.5)'))
display(Color('color(srgb 0 0 1 / 0.75)'))
display(Color('color(srgb 0 1 0 / 1)'))
Screenshot 2024-08-11 at 2 52 58 PM

@apcamargo
Copy link
Author

I just found out about w3c/csswg-drafts#9449. I wasn't really aware of this issue.

I think this looks good! I had forgotten about the transparency grid.

Personally, I'm not a big fan of ridge borders. But that's minor

@facelessuser
Copy link
Owner

Open to suggestions, we could do some kind of double border. I was more looking for something where the border stood out on light and dark backgrounds.

@facelessuser
Copy link
Owner

Yeah, we'll go with a double border:

Screenshot 2024-08-11 at 4 30 18 PM Screenshot 2024-08-11 at 4 30 33 PM

@apcamargo
Copy link
Author

Much better! Thanks for working on this so quickly :)

@facelessuser
Copy link
Owner

Much better! Thanks for working on this so quickly :)

Yeah, I'm not particularly fond of ridge either, but I also threw it together pretty quickly :).

I just found out about w3c/csswg-drafts#9449. I wasn't really aware of this issue.

Yeah, they are still trying to figure out how browsers will gamut map things. Basically what it boils down is CSS offers a proposal to gamut map and preserve lightness in a perceptual color space, which has many uses, but admittedly, it is not as good for image gamut mapping etc. Preserving chroma can be quite desirable with images. Some browsers want one GMA to rule them all, but supporting preserving chroma with GMA and preserving lightness with GMA are at odds with each other and have different use cases. There are also a lot of opinions on a great number of little details as well. I think Chrome is pushing hard to have some kind of baked in logic for each supported gamut while CSS has a generic (and slow) algorithm. Nobody has been super clear on what the criteria should be, so now it seems all the browsers are waiting to see what Chrome resolves with the CSS WG. Who knows what the final solution will look like.

There a lot of other opinions out there too about a great number of things.

@apcamargo
Copy link
Author

Thanks for the explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S: triage Issue needs triage.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants