Open strickvl opened 2 years ago
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.
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.
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.
@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.
If you need help why something doesn't work as you thought, you can ask here or in Discord.
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.
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"
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
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")
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.