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

Pleasant Default Colour Schema #211

Open
strickvl opened this issue Apr 28, 2022 · 9 comments
Open

Pleasant Default Colour Schema #211

strickvl opened this issue Apr 28, 2022 · 9 comments
Labels
enhancement New feature or request

Comments

@strickvl
Copy link
Contributor

I'd propose to include some smart / pleasant default colour schema as options that users could have at their fingertips, saving them looking up colour codes and assembling something that looks ok.

I'd be happy to implement this as a PR, if you'd be interested.

@emeli-dral
Copy link
Contributor

That sounds awesome, we’d be very happy to have it!

However, there is a thing I want to highlight. Together with https://github.com/evidentlyai/evidently/tree/main/src/evidently module, where we implement most of the package logic, we have https://github.com/evidentlyai/evidently/tree/main/ui part as well. Significant share of the visuals is specified there and it might be a bit difficult to customize it.
Honestly, that is a reason why we still did not support a Dark Scheme for the reports: the background colors is specified in UI and we do not have one particular place where we can specify it :(

Taking this into account I believe it will be much more convenient to implement default colour schemas on top of the available color constants: https://docs.evidentlyai.com/user-guide/customization/options-for-color-schema#available-options.

If you are willing to touch this UI part, you are very welcome too! Just wanted to mention that it might bring extra complexity.

@emeli-dral emeli-dral added the enhancement New feature or request label May 2, 2022
@strickvl
Copy link
Contributor Author

strickvl commented Jun 9, 2022

Probably the easiest way to implement some of these would be to do a series of ColorOptions definitions within the color_scheme.py file itself, perhaps like this:

# ... all the definitions of `ColorOptions` etc above...

def _set_color_options(_self, **kwargs):
    for k, v in kwargs.items():
        setattr(_self, k, v)


solarized_color_options = ColorOptions()

_set_color_options(
    solarized_color_options,
    primary_color="#268bd2",
    secondary_color="#073642",
    current_data_color="#268bd2",
    reference_data_color="#073642",
    color_sequence=[
        "#268bd2",
        "#2aa198",
        "#859900",
        "#b58900",
        "#cb4b16",
        "#dc322f",
    ],
)

I have maybe 5 or 10 different color schemes in mind that I could define this way. This way the user can just import them directly without having to define all the attributes.

I guess I'd update the docs, too, to reflect this change and show how people can use it.

@Liraim
Copy link
Collaborator

Liraim commented Jun 13, 2022

Hi @strickvl,

Yes it is good way to create predefined ColorOptions but you don't even need _set_color_options as you can write it as:

solarized_color_options  = ColorOptions(primary_color="#268bd2",
    secondary_color="#073642",
    current_data_color="#268bd2",
    reference_data_color="#073642",
    color_sequence=[
        "#268bd2",
        "#2aa198",
        "#859900",
        "#b58900",
        "#cb4b16",
        "#dc322f",
    ],
)

This would work the same, and if you skip some of fields it would use default one.

@strickvl
Copy link
Contributor Author

@Liraim Thanks. Yeah I had actually thought I could just set it directly, but I was hitting some errors around that. I'll take another look later on and see if I can implement this one way or another.

@Liraim
Copy link
Collaborator

Liraim commented Jun 13, 2022

If you need help why something doesn't work as you thought, you can ask here or in Discord.

@strickvl
Copy link
Contributor Author

I tried it the way you suggested, but I get the following error when trying to instantiate the object:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/Users/strickvl/coding/evidently/test.ipynb Cell 1' in <cell line: 1>()
----> 1 from evidently.options import ColorOptions
      2 from evidently.dashboard import Dashboard
      3 from evidently.dashboard.tabs import DataDriftTab

File ~/coding/evidently/src/evidently/options/__init__.py:3, in <module>
      1 from typing import TypeVar, Generic, Type, Dict, Any
----> 3 from .color_scheme import ColorOptions, solarized_color_options
      4 from .data_drift import DataDriftOptions
      5 from .quality_metrics import QualityMetricsOptions

File ~/coding/evidently/src/evidently/options/color_scheme.py:75, in <module>
     49         return self.reference_data_color or self.secondary_color
     52 # def _set_color_options(_self, **kwargs):
     53 #     for k, v in kwargs.items():
     54 #         setattr(_self, k, v)
   (...)
     72 #     ],
     73 # )
---> 75 solarized_color_options = ColorOptions(
     76     primary_color="#268bd2",
     77     secondary_color="#073642",
     78     current_data_color="#268bd2",
     79     reference_data_color="#073642",
     80     color_sequence=[
     81         "#268bd2",
     82         "#2aa198",
     83         "#859900",
     84         "#b58900",
     85         "#cb4b16",
     86         "#dc322f",
     87     ],
     88 )

TypeError: __init__() got an unexpected keyword argument 'primary_color'

This is the reason I decided to create a small helper method, @Liraim.

@Liraim
Copy link
Collaborator

Liraim commented Jun 18, 2022

Oh, I've missed that: there are no type hints for fields in ColorOptions class so dataclass do not create __init__ method with them. Probably, best solution would be add type hints for fields.

Something like this:

@dataclass
class ColorOptions:
    primary_color: str = RED
    secondary_color: str = GREY
    current_data_color: Optional[str] = None
    reference_data_color: Optional[str] = None
    color_sequence: List[str] = COLOR_DISCRETE_SEQUENCE
    fill_color: str = "LightGreen"
    zero_line_color: str = "green"
    non_visible_color: str = "white"
    underestimation_color: str = "#6574f7"
    overestimation_color: str = "#ee5540"
    majority_color: str = "#1acc98"

@strickvl
Copy link
Contributor Author

Ah yes, you're right. The only part that remains a bit tricky is using a mutable default value. For color_sequence it seems I have to do something like this:

color_sequence: list = field(
        default_factory=lambda: COLOR_DISCRETE_SEQUENCE
    )

but on instantiating the object I get this error:

TypeError: 'list' object is not callable

@Liraim
Copy link
Collaborator

Liraim commented Jun 18, 2022

You can change COLOR_DISCRETE_SEQUENCE from list to tuple (immutable), so you will be able to use it directly as before.

COLOR_DISCRETE_SEQUENCE = ("#ed0400", "#0a5f38", "#6c3461", "#71aa34", "#d8dcd6", "#6b8ba4")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants