Repository: arviz-devs/arviz

Issue:
Bokeh, transform all colors to hex
Input all colors to bokeh functions as hex.

We can use matplotlib helper functions to transform special syntax

    color="C0"

etc


Discussion:
@OriolAbril can I try fixing it?
@mrinalnilotpal Definitely! 
can anybody tell me which files I should look at in order to solve the issue?
I think you would need to create a function that transforms certain colors (rgb, 'C{i}' syntax etc to hex)

These are for bokeh plots
matplotlib have some functions for color conversion. https://matplotlib.org/api/colors_api.html#functions and the "CN" colors can be accessed from `matplotlib.rcParams['axes.prop_cycle']`
Is this issue still to be resolved?

@mrinalnilotpal @animesh-007 @sahajsk21 It is still pending. Just to make sure it is clear what this PR entails, I'll try to extend the description. The goal is to have some easy way to convert all kinds of colors used by matplotlib (such as `C0, C1` to refer to default colors in prop_cycle, named colors, single letter color abbreviations, rgb...) to hex in order to use them in bokeh. Then, modify the code where necessary to make both backends plot the same colors (which is currently not the case, e.g. [matplotlib's ppc](https://arviz-devs.github.io/arviz/examples/matplotlib/mpl_plot_ppc.html) vs [bokeh's ppc](https://arviz-devs.github.io/arviz/examples/bokeh/bokeh_plot_ppc.html)

It looks like [`to_hex`](https://matplotlib.org/api/_as_gen/matplotlib.colors.to_hex.html#matplotlib.colors.to_hex) is exactly what we are looking for. I think a way to tackle this would be to convert all color references to hex before passing them to the backend files. Then both backends should plot the same colors without much hassle. 
Thanks @OriolAbril I'll be working to solve this issue
@OriolAbril  I think this issue has been inactive for a while. Could I work on it?
@sahajsk21 do you still plan to work on this? 
@amukh18 @OriolAbril I have been working on issue so he can take up the issue.Thanks
> I have been working on issue so he **can't** take up the issue.Thanks

Could there be a typo so the message is this? @sahajsk21 There is no rush, work at your own pace, this is why we ask :). 

Sorry if my previous wording sounded harsh, it wasn't the intention. Also, please let us know if you were to need any help


@OriolAbril No it wasn't a typo. Don't worry, I didn't take the comment in the negative sense. Actually, I have been going through the code and making myself familiar first before working on the issue. That is why it is taking so long.
But I think @amukh18 can still take up this issue.

> @amukh18 @OriolAbril I have been working on another issue so he can take up the issue. Thanks


@sahajsk21 @OriolAbril Thank you. I'll begin working on it right away.
@OriolAbril  I have a question. If I were to add the to_hex function to plot_khat as follows:
```
if hlines_kwargs is None:
        hlines_kwargs = {}
    hlines_kwargs.setdefault("linestyle", [":", "-.", "--", "-"])
    hlines_kwargs.setdefault("alpha", 0.7)
    hlines_kwargs.setdefault("zorder", -1)
    hlines_kwargs.setdefault("color", to_hex("C1"))

    if coords is None:
        coords = {}

    if color is None:
        color = "C0"
    color = to_hex(color)
```
Is this supposed to return any errors?
I think this should work for this case
Hmm, pytest returned some errors. I will see what the unit tests on the pipeline say on committing.

Resolving patch:
diff --git a/arviz/plots/khatplot.py b/arviz/plots/khatplot.py
--- a/arviz/plots/khatplot.py
+++ b/arviz/plots/khatplot.py
@@ -11,6 +11,7 @@
     format_coords_as_labels,
     get_plotting_function,
     matplotlib_kwarg_dealiaser,
+    vectorized_to_hex,
 )
 from ..stats import ELPDData
 from ..rcparams import rcParams
@@ -138,6 +139,7 @@ def plot_khat(
     hlines_kwargs.setdefault("alpha", 0.7)
     hlines_kwargs.setdefault("zorder", -1)
     hlines_kwargs.setdefault("color", "C1")
+    hlines_kwargs["color"] = vectorized_to_hex(hlines_kwargs["color"])
 
     if coords is None:
         coords = {}
@@ -200,6 +202,7 @@ def plot_khat(
     khats = khats if isinstance(khats, np.ndarray) else khats.values.flatten()
     alphas = 0.5 + 0.2 * (khats > 0.5) + 0.3 * (khats > 1)
     rgba_c[:, 3] = alphas
+    rgba_c = vectorized_to_hex(rgba_c)
 
     plot_khat_kwargs = dict(
         hover_label=hover_label,
diff --git a/arviz/plots/plot_utils.py b/arviz/plots/plot_utils.py
--- a/arviz/plots/plot_utils.py
+++ b/arviz/plots/plot_utils.py
@@ -4,6 +4,7 @@
 from itertools import product, tee
 import importlib
 from scipy.stats import mode
+from matplotlib.colors import to_hex
 
 import packaging
 import numpy as np
@@ -468,7 +469,7 @@ def color_from_dim(dataarray, dim_name):
     ----------
     dataarray : xarray.DataArray
     dim_name : str
-        dimension whose coordinates will be used as color code.
+    dimension whose coordinates will be used as color code.
 
     Returns
     -------
@@ -490,6 +491,28 @@ def color_from_dim(dataarray, dim_name):
     return colors, color_mapping
 
 
+def vectorized_to_hex(c_values, keep_alpha=False):
+    """Convert a color (including vector of colors) to hex.
+
+    Parameters
+    ----------
+    c: Matplotlib color
+
+    keep_alpha: boolean
+        to select if alpha values should be kept in the final hex values.
+
+    Returns
+    -------
+    rgba_hex : vector of hex values
+    """
+    try:
+        hex_color = to_hex(c_values, keep_alpha)
+
+    except ValueError:
+        hex_color = [to_hex(color, keep_alpha) for color in c_values]
+    return hex_color
+
+
 def format_coords_as_labels(dataarray, skip_dims=None):
     """Format 1d or multi-d dataarray coords as strings.
 


Test patch:
diff --git a/arviz/tests/base_tests/test_plot_utils.py b/arviz/tests/base_tests/test_plot_utils.py
--- a/arviz/tests/base_tests/test_plot_utils.py
+++ b/arviz/tests/base_tests/test_plot_utils.py
@@ -15,6 +15,7 @@
     matplotlib_kwarg_dealiaser,
     xarray_to_ndarray,
     xarray_var_iter,
+    vectorized_to_hex,
 )
 from ...rcparams import rc_context
 from ...numeric_utils import get_bins
@@ -229,3 +230,17 @@ def test_matplotlib_kwarg_dealiaser(params):
     dealiased = matplotlib_kwarg_dealiaser(params["input"][0], kind=params["input"][1])
     for returned in dealiased:
         assert returned in params["output"]
+
+
+@pytest.mark.parametrize("c_values", ["#0000ff", "blue", [0, 0, 1]])
+def test_vectorized_to_hex_scalar(c_values):
+    output = vectorized_to_hex(c_values)
+    assert output == "#0000ff"
+
+
+@pytest.mark.parametrize(
+    "c_values", [["blue", "blue"], ["blue", "#0000ff"], np.array([[0, 0, 1], [0, 0, 1]])]
+)
+def test_vectorized_to_hex_array(c_values):
+    output = vectorized_to_hex(c_values)
+    assert np.all([item == "#0000ff" for item in output])