Repository: plotly/plotly.py

Issue:
create_annotated_heatmap throws on rgba in colorscale
```py
import plotly.figure_factory as ff

z = [
    [0.1, 0.3, 0.5, 0.7, 0.9],
    [1, 0.8, 0.6, 0.4, 0.2],
    [0.2, 0, 0.5, 0.7, 0.9],
    [0.9, 0.8, 0.4, 0.2, 0],
    [0.3, 0.4, 0.5, 0.7, 1],
]

# works
ff.create_annotated_heatmap(z, colorscale=[(0, "rgb(0, 0, 0)"), (1, "green")])
# throws error
ff.create_annotated_heatmap(z, colorscale=[(0, "rgba(0, 0, 0, 0)"), (1, "green")])
```

**Full stack trace**

```py
t.py in <module>
----> 62 ff.create_annotated_heatmap(
      63     z,
      64     colorscale=[(0, "rgba(0, 0, 0, 0)"), (1, "green")],
      65 )
      66 

plotly/figure_factory/_annotated_heatmap.py in create_annotated_heatmap(z, x, y, annotation_text, colorscale, font_colors, showscale, reversescale, **kwargs)
    105     colorscale = colorscale_validator.validate_coerce(colorscale)
    106 
--> 107     annotations = _AnnotatedHeatmap(
    108         z, x, y, annotation_text, colorscale, font_colors, reversescale, **kwargs
    109     ).make_annotations()

plotly/figure_factory/_annotated_heatmap.py in make_annotations(self)
    289             the heatmap
    290         """
--> 291         min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)
    292         annotations = []
    293         for n, row in enumerate(self.z):

plotly/figure_factory/_annotated_heatmap.py in get_text_color(self)
    261         elif isinstance(self.colorscale, list):
    262 
--> 263             min_col = to_rgb_color_list(self.colorscale[0][1], [255, 255, 255])
    264             max_col = to_rgb_color_list(self.colorscale[-1][1], [255, 255, 255])
    265 

plotly/figure_factory/_annotated_heatmap.py in to_rgb_color_list(color_str, default)
    149 def to_rgb_color_list(color_str, default):
    150     if "rgb" in color_str:
--> 151         return [int(v) for v in color_str.strip("rgb()").split(",")]
    152     elif "#" in color_str:
    153         return clrs.hex_to_rgb(color_str)

plotly/figure_factory/_annotated_heatmap.py in <listcomp>(.0)
    149 def to_rgb_color_list(color_str, default):
    150     if "rgb" in color_str:
--> 151         return [int(v) for v in color_str.strip("rgb()").split(",")]
    152     elif "#" in color_str:
    153         return clrs.hex_to_rgb(color_str)

ValueError: invalid literal for int() with base 10: 'a(0'
```
create_annotated_heatmap throws on rgba in colorscale
```py
import plotly.figure_factory as ff

z = [
    [0.1, 0.3, 0.5, 0.7, 0.9],
    [1, 0.8, 0.6, 0.4, 0.2],
    [0.2, 0, 0.5, 0.7, 0.9],
    [0.9, 0.8, 0.4, 0.2, 0],
    [0.3, 0.4, 0.5, 0.7, 1],
]

# works
ff.create_annotated_heatmap(z, colorscale=[(0, "rgb(0, 0, 0)"), (1, "green")])
# throws error
ff.create_annotated_heatmap(z, colorscale=[(0, "rgba(0, 0, 0, 0)"), (1, "green")])
```

**Full stack trace**

```py
t.py in <module>
----> 62 ff.create_annotated_heatmap(
      63     z,
      64     colorscale=[(0, "rgba(0, 0, 0, 0)"), (1, "green")],
      65 )
      66 

plotly/figure_factory/_annotated_heatmap.py in create_annotated_heatmap(z, x, y, annotation_text, colorscale, font_colors, showscale, reversescale, **kwargs)
    105     colorscale = colorscale_validator.validate_coerce(colorscale)
    106 
--> 107     annotations = _AnnotatedHeatmap(
    108         z, x, y, annotation_text, colorscale, font_colors, reversescale, **kwargs
    109     ).make_annotations()

plotly/figure_factory/_annotated_heatmap.py in make_annotations(self)
    289             the heatmap
    290         """
--> 291         min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)
    292         annotations = []
    293         for n, row in enumerate(self.z):

plotly/figure_factory/_annotated_heatmap.py in get_text_color(self)
    261         elif isinstance(self.colorscale, list):
    262 
--> 263             min_col = to_rgb_color_list(self.colorscale[0][1], [255, 255, 255])
    264             max_col = to_rgb_color_list(self.colorscale[-1][1], [255, 255, 255])
    265 

plotly/figure_factory/_annotated_heatmap.py in to_rgb_color_list(color_str, default)
    149 def to_rgb_color_list(color_str, default):
    150     if "rgb" in color_str:
--> 151         return [int(v) for v in color_str.strip("rgb()").split(",")]
    152     elif "#" in color_str:
    153         return clrs.hex_to_rgb(color_str)

plotly/figure_factory/_annotated_heatmap.py in <listcomp>(.0)
    149 def to_rgb_color_list(color_str, default):
    150     if "rgb" in color_str:
--> 151         return [int(v) for v in color_str.strip("rgb()").split(",")]
    152     elif "#" in color_str:
    153         return clrs.hex_to_rgb(color_str)

ValueError: invalid literal for int() with base 10: 'a(0'
```


Discussion:

Resolving patch:
diff --git a/packages/python/plotly/plotly/figure_factory/_annotated_heatmap.py b/packages/python/plotly/plotly/figure_factory/_annotated_heatmap.py
--- a/packages/python/plotly/plotly/figure_factory/_annotated_heatmap.py
+++ b/packages/python/plotly/plotly/figure_factory/_annotated_heatmap.py
@@ -1,7 +1,7 @@
 from __future__ import absolute_import, division
 
-from plotly import exceptions, optional_imports
 import plotly.colors as clrs
+from plotly import exceptions, optional_imports
 from plotly.figure_factory import utils
 from plotly.graph_objs import graph_objs
 from plotly.validators.heatmap import ColorscaleValidator
@@ -150,9 +150,10 @@ def create_annotated_heatmap(
 
 
 def to_rgb_color_list(color_str, default):
-    if "rgb" in color_str:
-        return [int(v) for v in color_str.strip("rgb()").split(",")]
-    elif "#" in color_str:
+    color_str = color_str.strip()
+    if color_str.startswith("rgb"):
+        return [int(v) for v in color_str.strip("rgba()").split(",")]
+    elif color_str.startswith("#"):
         return clrs.hex_to_rgb(color_str)
     else:
         return default


Test patch: