We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Annotated heatmaps: font colour blends with the colour of the square.
When using the default color scheme, the font color contrasts normally with the fill of the each heatmap square. But if you try other standard color schemes with `reversescale=True`, when values are close to zero, the colors will merge. I think this is the wrong default behavior.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plotly/figure_factory/_annotated_heatmap.py`
Content:
```
1 from __future__ import absolute_import
2 
3 from plotly import exceptions, optional_imports
4 import plotly.colors as clrs
5 from plotly.figure_factory import utils
6 from plotly.graph_objs import graph_objs
7 from plotly.validators.heatmap import ColorscaleValidator
8 
9 # Optional imports, may be None for users that only use our core functionality.
10 np = optional_imports.get_module('numpy')
11 
12 
13 def validate_annotated_heatmap(z, x, y, annotation_text):
14     """
15     Annotated-heatmap-specific validations
16 
17     Check that if a text matrix is supplied, it has the same
18     dimensions as the z matrix.
19 
20     See FigureFactory.create_annotated_heatmap() for params
21 
22     :raises: (PlotlyError) If z and text matrices do not  have the same
23         dimensions.
24     """
25     if annotation_text is not None and isinstance(annotation_text, list):
26         utils.validate_equal_length(z, annotation_text)
27         for lst in range(len(z)):
28             if len(z[lst]) != len(annotation_text[lst]):
29                 raise exceptions.PlotlyError("z and text should have the "
30                                              "same dimensions")
31 
32     if x:
33         if len(x) != len(z[0]):
34             raise exceptions.PlotlyError("oops, the x list that you "
35                                          "provided does not match the "
36                                          "width of your z matrix ")
37 
38     if y:
39         if len(y) != len(z):
40             raise exceptions.PlotlyError("oops, the y list that you "
41                                          "provided does not match the "
42                                          "length of your z matrix ")
43 
44 
45 def create_annotated_heatmap(z, x=None, y=None, annotation_text=None,
46                              colorscale='RdBu', font_colors=None,
47                              showscale=False, reversescale=False,
48                              **kwargs):
49     """
50     BETA function that creates annotated heatmaps
51 
52     This function adds annotations to each cell of the heatmap.
53 
54     :param (list[list]|ndarray) z: z matrix to create heatmap.
55     :param (list) x: x axis labels.
56     :param (list) y: y axis labels.
57     :param (list[list]|ndarray) annotation_text: Text strings for
58         annotations. Should have the same dimensions as the z matrix. If no
59         text is added, the values of the z matrix are annotated. Default =
60         z matrix values.
61     :param (list|str) colorscale: heatmap colorscale.
62     :param (list) font_colors: List of two color strings: [min_text_color,
63         max_text_color] where min_text_color is applied to annotations for
64         heatmap values < (max_value - min_value)/2. If font_colors is not
65         defined, the colors are defined logically as black or white
66         depending on the heatmap's colorscale.
67     :param (bool) showscale: Display colorscale. Default = False
68     :param (bool) reversescale: Reverse colorscale. Default = False
69     :param kwargs: kwargs passed through plotly.graph_objs.Heatmap.
70         These kwargs describe other attributes about the annotated Heatmap
71         trace such as the colorscale. For more information on valid kwargs
72         call help(plotly.graph_objs.Heatmap)
73 
74     Example 1: Simple annotated heatmap with default configuration
75     ```
76     import plotly.plotly as py
77     import plotly.figure_factory as FF
78 
79     z = [[0.300000, 0.00000, 0.65, 0.300000],
80          [1, 0.100005, 0.45, 0.4300],
81          [0.300000, 0.00000, 0.65, 0.300000],
82          [1, 0.100005, 0.45, 0.00000]]
83 
84     figure = FF.create_annotated_heatmap(z)
85     py.iplot(figure)
86     ```
87     """
88 
89     # Avoiding mutables in the call signature
90     font_colors = font_colors if font_colors is not None else []
91     validate_annotated_heatmap(z, x, y, annotation_text)
92 
93     # validate colorscale
94     colorscale_validator = ColorscaleValidator()
95     colorscale = colorscale_validator.validate_coerce(colorscale)
96 
97     annotations = _AnnotatedHeatmap(z, x, y, annotation_text,
98                                     colorscale, font_colors, reversescale,
99                                     **kwargs).make_annotations()
100 
101     if x or y:
102         trace = dict(type='heatmap', z=z, x=x, y=y, colorscale=colorscale,
103                      showscale=showscale, reversescale=reversescale, **kwargs)
104         layout = dict(annotations=annotations,
105                       xaxis=dict(ticks='', dtick=1, side='top',
106                                  gridcolor='rgb(0, 0, 0)'),
107                       yaxis=dict(ticks='', dtick=1, ticksuffix='  '))
108     else:
109         trace = dict(type='heatmap', z=z, colorscale=colorscale,
110                      showscale=showscale, reversescale=reversescale, **kwargs)
111         layout = dict(annotations=annotations,
112                       xaxis=dict(ticks='', side='top',
113                                  gridcolor='rgb(0, 0, 0)',
114                                  showticklabels=False),
115                       yaxis=dict(ticks='', ticksuffix='  ',
116                                  showticklabels=False))
117 
118     data = [trace]
119 
120     return graph_objs.Figure(data=data, layout=layout)
121 
122 
123 def to_rgb_color_list(color_str, default):
124     if 'rgb' in color_str:
125         return [int(v) for v in color_str.strip('rgb()').split(',')]
126     elif '#' in color_str:
127         return clrs.hex_to_rgb(color_str)
128     else:
129         return default
130 
131 
132 def should_use_black_text(background_color):
133     return (background_color[0] * 0.299 +
134             background_color[1] * 0.587 +
135             background_color[2] * 0.114) > 186
136 
137 
138 class _AnnotatedHeatmap(object):
139     """
140     Refer to TraceFactory.create_annotated_heatmap() for docstring
141     """
142     def __init__(self, z, x, y, annotation_text, colorscale,
143                  font_colors, reversescale, **kwargs):
144 
145         self.z = z
146         if x:
147             self.x = x
148         else:
149             self.x = range(len(z[0]))
150         if y:
151             self.y = y
152         else:
153             self.y = range(len(z))
154         if annotation_text is not None:
155             self.annotation_text = annotation_text
156         else:
157             self.annotation_text = self.z
158         self.colorscale = colorscale
159         self.reversescale = reversescale
160         self.font_colors = font_colors
161 
162     def get_text_color(self):
163         """
164         Get font color for annotations.
165 
166         The annotated heatmap can feature two text colors: min_text_color and
167         max_text_color. The min_text_color is applied to annotations for
168         heatmap values < (max_value - min_value)/2. The user can define these
169         two colors. Otherwise the colors are defined logically as black or
170         white depending on the heatmap's colorscale.
171 
172         :rtype (string, string) min_text_color, max_text_color: text
173             color for annotations for heatmap values <
174             (max_value - min_value)/2 and text color for annotations for
175             heatmap values >= (max_value - min_value)/2
176         """
177         # Plotly colorscales ranging from a lighter shade to a darker shade
178         colorscales = ['Greys', 'Greens', 'Blues',
179                        'YIGnBu', 'YIOrRd', 'RdBu',
180                        'Picnic', 'Jet', 'Hot', 'Blackbody',
181                        'Earth', 'Electric', 'Viridis', 'Cividis']
182         # Plotly colorscales ranging from a darker shade to a lighter shade
183         colorscales_reverse = ['Reds']
184 
185         white = '#FFFFFF'
186         black = '#000000'
187         if self.font_colors:
188             min_text_color = self.font_colors[0]
189             max_text_color = self.font_colors[-1]
190         elif self.colorscale in colorscales and self.reversescale:
191             min_text_color = black
192             max_text_color = white
193         elif self.colorscale in colorscales:
194             min_text_color = white
195             max_text_color = black
196         elif self.colorscale in colorscales_reverse and self.reversescale:
197             min_text_color = white
198             max_text_color = black
199         elif self.colorscale in colorscales_reverse:
200             min_text_color = black
201             max_text_color = white
202         elif isinstance(self.colorscale, list):
203 
204             min_col = to_rgb_color_list(self.colorscale[0][1],
205                                         [255, 255, 255])
206             max_col = to_rgb_color_list(self.colorscale[-1][1],
207                                         [255, 255, 255])
208 
209             # swap min/max colors if reverse scale
210             if self.reversescale:
211                 min_col, max_col = max_col, min_col
212 
213             if should_use_black_text(min_col):
214                 min_text_color = black
215             else:
216                 min_text_color = white
217 
218             if should_use_black_text(max_col):
219                 max_text_color = black
220             else:
221                 max_text_color = white
222         else:
223             min_text_color = black
224             max_text_color = black
225         return min_text_color, max_text_color
226 
227     def get_z_mid(self):
228         """
229         Get the mid value of z matrix
230 
231         :rtype (float) z_avg: average val from z matrix
232         """
233         if np and isinstance(self.z, np.ndarray):
234             z_min = np.amin(self.z)
235             z_max = np.amax(self.z)
236         else:
237             z_min = min(min(self.z))
238             z_max = max(max(self.z))
239         z_mid = (z_max+z_min) / 2
240         return z_mid
241 
242     def make_annotations(self):
243         """
244         Get annotations for each cell of the heatmap with graph_objs.Annotation
245 
246         :rtype (list[dict]) annotations: list of annotations for each cell of
247             the heatmap
248         """
249         min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)
250         z_mid = _AnnotatedHeatmap.get_z_mid(self)
251         annotations = []
252         for n, row in enumerate(self.z):
253             for m, val in enumerate(row):
254                 font_color = min_text_color if val < z_mid else max_text_color
255                 annotations.append(
256                     graph_objs.layout.Annotation(
257                         text=str(self.annotation_text[n][m]),
258                         x=self.x[m],
259                         y=self.y[n],
260                         xref='x1',
261                         yref='y1',
262                         font=dict(color=font_color),
263                         showarrow=False))
264         return annotations
265
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plotly/figure_factory/_annotated_heatmap.py b/plotly/figure_factory/_annotated_heatmap.py
--- a/plotly/figure_factory/_annotated_heatmap.py
+++ b/plotly/figure_factory/_annotated_heatmap.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import absolute_import, division
 
 from plotly import exceptions, optional_imports
 import plotly.colors as clrs
@@ -234,8 +234,8 @@
             z_min = np.amin(self.z)
             z_max = np.amax(self.z)
         else:
-            z_min = min(min(self.z))
-            z_max = max(max(self.z))
+            z_min = min([v for row in self.z for v in row])
+            z_max = max([v for row in self.z for v in row])
         z_mid = (z_max+z_min) / 2
         return z_mid

{"golden_diff": "diff --git a/plotly/figure_factory/_annotated_heatmap.py b/plotly/figure_factory/_annotated_heatmap.py\n--- a/plotly/figure_factory/_annotated_heatmap.py\n+++ b/plotly/figure_factory/_annotated_heatmap.py\n@@ -1,4 +1,4 @@\n-from __future__ import absolute_import\n+from __future__ import absolute_import, division\n \n from plotly import exceptions, optional_imports\n import plotly.colors as clrs\n@@ -234,8 +234,8 @@\n             z_min = np.amin(self.z)\n             z_max = np.amax(self.z)\n         else:\n-            z_min = min(min(self.z))\n-            z_max = max(max(self.z))\n+            z_min = min([v for row in self.z for v in row])\n+            z_max = max([v for row in self.z for v in row])\n         z_mid = (z_max+z_min) / 2\n         return z_mid\n", "issue": "Annotated heatmaps: font colour blends with the colour of the square.\nWhen using the default color scheme, the font color contrasts normally with the fill of the each heatmap square. But if you try other standard color schemes with `reversescale=True`, when values are close to zero, the colors will merge. I think this is the wrong default behavior.\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom plotly import exceptions, optional_imports\nimport plotly.colors as clrs\nfrom plotly.figure_factory import utils\nfrom plotly.graph_objs import graph_objs\nfrom plotly.validators.heatmap import ColorscaleValidator\n\n# Optional imports, may be None for users that only use our core functionality.\nnp = optional_imports.get_module('numpy')\n\n\ndef validate_annotated_heatmap(z, x, y, annotation_text):\n    \"\"\"\n    Annotated-heatmap-specific validations\n\n    Check that if a text matrix is supplied, it has the same\n    dimensions as the z matrix.\n\n    See FigureFactory.create_annotated_heatmap() for params\n\n    :raises: (PlotlyError) If z and text matrices do not  have the same\n        dimensions.\n    \"\"\"\n    if annotation_text is not None and isinstance(annotation_text, list):\n        utils.validate_equal_length(z, annotation_text)\n        for lst in range(len(z)):\n            if len(z[lst]) != len(annotation_text[lst]):\n                raise exceptions.PlotlyError(\"z and text should have the \"\n                                             \"same dimensions\")\n\n    if x:\n        if len(x) != len(z[0]):\n            raise exceptions.PlotlyError(\"oops, the x list that you \"\n                                         \"provided does not match the \"\n                                         \"width of your z matrix \")\n\n    if y:\n        if len(y) != len(z):\n            raise exceptions.PlotlyError(\"oops, the y list that you \"\n                                         \"provided does not match the \"\n                                         \"length of your z matrix \")\n\n\ndef create_annotated_heatmap(z, x=None, y=None, annotation_text=None,\n                             colorscale='RdBu', font_colors=None,\n                             showscale=False, reversescale=False,\n                             **kwargs):\n    \"\"\"\n    BETA function that creates annotated heatmaps\n\n    This function adds annotations to each cell of the heatmap.\n\n    :param (list[list]|ndarray) z: z matrix to create heatmap.\n    :param (list) x: x axis labels.\n    :param (list) y: y axis labels.\n    :param (list[list]|ndarray) annotation_text: Text strings for\n        annotations. Should have the same dimensions as the z matrix. If no\n        text is added, the values of the z matrix are annotated. Default =\n        z matrix values.\n    :param (list|str) colorscale: heatmap colorscale.\n    :param (list) font_colors: List of two color strings: [min_text_color,\n        max_text_color] where min_text_color is applied to annotations for\n        heatmap values < (max_value - min_value)/2. If font_colors is not\n        defined, the colors are defined logically as black or white\n        depending on the heatmap's colorscale.\n    :param (bool) showscale: Display colorscale. Default = False\n    :param (bool) reversescale: Reverse colorscale. Default = False\n    :param kwargs: kwargs passed through plotly.graph_objs.Heatmap.\n        These kwargs describe other attributes about the annotated Heatmap\n        trace such as the colorscale. For more information on valid kwargs\n        call help(plotly.graph_objs.Heatmap)\n\n    Example 1: Simple annotated heatmap with default configuration\n    ```\n    import plotly.plotly as py\n    import plotly.figure_factory as FF\n\n    z = [[0.300000, 0.00000, 0.65, 0.300000],\n         [1, 0.100005, 0.45, 0.4300],\n         [0.300000, 0.00000, 0.65, 0.300000],\n         [1, 0.100005, 0.45, 0.00000]]\n\n    figure = FF.create_annotated_heatmap(z)\n    py.iplot(figure)\n    ```\n    \"\"\"\n\n    # Avoiding mutables in the call signature\n    font_colors = font_colors if font_colors is not None else []\n    validate_annotated_heatmap(z, x, y, annotation_text)\n\n    # validate colorscale\n    colorscale_validator = ColorscaleValidator()\n    colorscale = colorscale_validator.validate_coerce(colorscale)\n\n    annotations = _AnnotatedHeatmap(z, x, y, annotation_text,\n                                    colorscale, font_colors, reversescale,\n                                    **kwargs).make_annotations()\n\n    if x or y:\n        trace = dict(type='heatmap', z=z, x=x, y=y, colorscale=colorscale,\n                     showscale=showscale, reversescale=reversescale, **kwargs)\n        layout = dict(annotations=annotations,\n                      xaxis=dict(ticks='', dtick=1, side='top',\n                                 gridcolor='rgb(0, 0, 0)'),\n                      yaxis=dict(ticks='', dtick=1, ticksuffix='  '))\n    else:\n        trace = dict(type='heatmap', z=z, colorscale=colorscale,\n                     showscale=showscale, reversescale=reversescale, **kwargs)\n        layout = dict(annotations=annotations,\n                      xaxis=dict(ticks='', side='top',\n                                 gridcolor='rgb(0, 0, 0)',\n                                 showticklabels=False),\n                      yaxis=dict(ticks='', ticksuffix='  ',\n                                 showticklabels=False))\n\n    data = [trace]\n\n    return graph_objs.Figure(data=data, layout=layout)\n\n\ndef to_rgb_color_list(color_str, default):\n    if 'rgb' in color_str:\n        return [int(v) for v in color_str.strip('rgb()').split(',')]\n    elif '#' in color_str:\n        return clrs.hex_to_rgb(color_str)\n    else:\n        return default\n\n\ndef should_use_black_text(background_color):\n    return (background_color[0] * 0.299 +\n            background_color[1] * 0.587 +\n            background_color[2] * 0.114) > 186\n\n\nclass _AnnotatedHeatmap(object):\n    \"\"\"\n    Refer to TraceFactory.create_annotated_heatmap() for docstring\n    \"\"\"\n    def __init__(self, z, x, y, annotation_text, colorscale,\n                 font_colors, reversescale, **kwargs):\n\n        self.z = z\n        if x:\n            self.x = x\n        else:\n            self.x = range(len(z[0]))\n        if y:\n            self.y = y\n        else:\n            self.y = range(len(z))\n        if annotation_text is not None:\n            self.annotation_text = annotation_text\n        else:\n            self.annotation_text = self.z\n        self.colorscale = colorscale\n        self.reversescale = reversescale\n        self.font_colors = font_colors\n\n    def get_text_color(self):\n        \"\"\"\n        Get font color for annotations.\n\n        The annotated heatmap can feature two text colors: min_text_color and\n        max_text_color. The min_text_color is applied to annotations for\n        heatmap values < (max_value - min_value)/2. The user can define these\n        two colors. Otherwise the colors are defined logically as black or\n        white depending on the heatmap's colorscale.\n\n        :rtype (string, string) min_text_color, max_text_color: text\n            color for annotations for heatmap values <\n            (max_value - min_value)/2 and text color for annotations for\n            heatmap values >= (max_value - min_value)/2\n        \"\"\"\n        # Plotly colorscales ranging from a lighter shade to a darker shade\n        colorscales = ['Greys', 'Greens', 'Blues',\n                       'YIGnBu', 'YIOrRd', 'RdBu',\n                       'Picnic', 'Jet', 'Hot', 'Blackbody',\n                       'Earth', 'Electric', 'Viridis', 'Cividis']\n        # Plotly colorscales ranging from a darker shade to a lighter shade\n        colorscales_reverse = ['Reds']\n\n        white = '#FFFFFF'\n        black = '#000000'\n        if self.font_colors:\n            min_text_color = self.font_colors[0]\n            max_text_color = self.font_colors[-1]\n        elif self.colorscale in colorscales and self.reversescale:\n            min_text_color = black\n            max_text_color = white\n        elif self.colorscale in colorscales:\n            min_text_color = white\n            max_text_color = black\n        elif self.colorscale in colorscales_reverse and self.reversescale:\n            min_text_color = white\n            max_text_color = black\n        elif self.colorscale in colorscales_reverse:\n            min_text_color = black\n            max_text_color = white\n        elif isinstance(self.colorscale, list):\n\n            min_col = to_rgb_color_list(self.colorscale[0][1],\n                                        [255, 255, 255])\n            max_col = to_rgb_color_list(self.colorscale[-1][1],\n                                        [255, 255, 255])\n\n            # swap min/max colors if reverse scale\n            if self.reversescale:\n                min_col, max_col = max_col, min_col\n\n            if should_use_black_text(min_col):\n                min_text_color = black\n            else:\n                min_text_color = white\n\n            if should_use_black_text(max_col):\n                max_text_color = black\n            else:\n                max_text_color = white\n        else:\n            min_text_color = black\n            max_text_color = black\n        return min_text_color, max_text_color\n\n    def get_z_mid(self):\n        \"\"\"\n        Get the mid value of z matrix\n\n        :rtype (float) z_avg: average val from z matrix\n        \"\"\"\n        if np and isinstance(self.z, np.ndarray):\n            z_min = np.amin(self.z)\n            z_max = np.amax(self.z)\n        else:\n            z_min = min(min(self.z))\n            z_max = max(max(self.z))\n        z_mid = (z_max+z_min) / 2\n        return z_mid\n\n    def make_annotations(self):\n        \"\"\"\n        Get annotations for each cell of the heatmap with graph_objs.Annotation\n\n        :rtype (list[dict]) annotations: list of annotations for each cell of\n            the heatmap\n        \"\"\"\n        min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)\n        z_mid = _AnnotatedHeatmap.get_z_mid(self)\n        annotations = []\n        for n, row in enumerate(self.z):\n            for m, val in enumerate(row):\n                font_color = min_text_color if val < z_mid else max_text_color\n                annotations.append(\n                    graph_objs.layout.Annotation(\n                        text=str(self.annotation_text[n][m]),\n                        x=self.x[m],\n                        y=self.y[n],\n                        xref='x1',\n                        yref='y1',\n                        font=dict(color=font_color),\n                        showarrow=False))\n        return annotations\n", "path": "plotly/figure_factory/_annotated_heatmap.py"}], "after_files": [{"content": "from __future__ import absolute_import, division\n\nfrom plotly import exceptions, optional_imports\nimport plotly.colors as clrs\nfrom plotly.figure_factory import utils\nfrom plotly.graph_objs import graph_objs\nfrom plotly.validators.heatmap import ColorscaleValidator\n\n# Optional imports, may be None for users that only use our core functionality.\nnp = optional_imports.get_module('numpy')\n\n\ndef validate_annotated_heatmap(z, x, y, annotation_text):\n    \"\"\"\n    Annotated-heatmap-specific validations\n\n    Check that if a text matrix is supplied, it has the same\n    dimensions as the z matrix.\n\n    See FigureFactory.create_annotated_heatmap() for params\n\n    :raises: (PlotlyError) If z and text matrices do not  have the same\n        dimensions.\n    \"\"\"\n    if annotation_text is not None and isinstance(annotation_text, list):\n        utils.validate_equal_length(z, annotation_text)\n        for lst in range(len(z)):\n            if len(z[lst]) != len(annotation_text[lst]):\n                raise exceptions.PlotlyError(\"z and text should have the \"\n                                             \"same dimensions\")\n\n    if x:\n        if len(x) != len(z[0]):\n            raise exceptions.PlotlyError(\"oops, the x list that you \"\n                                         \"provided does not match the \"\n                                         \"width of your z matrix \")\n\n    if y:\n        if len(y) != len(z):\n            raise exceptions.PlotlyError(\"oops, the y list that you \"\n                                         \"provided does not match the \"\n                                         \"length of your z matrix \")\n\n\ndef create_annotated_heatmap(z, x=None, y=None, annotation_text=None,\n                             colorscale='RdBu', font_colors=None,\n                             showscale=False, reversescale=False,\n                             **kwargs):\n    \"\"\"\n    BETA function that creates annotated heatmaps\n\n    This function adds annotations to each cell of the heatmap.\n\n    :param (list[list]|ndarray) z: z matrix to create heatmap.\n    :param (list) x: x axis labels.\n    :param (list) y: y axis labels.\n    :param (list[list]|ndarray) annotation_text: Text strings for\n        annotations. Should have the same dimensions as the z matrix. If no\n        text is added, the values of the z matrix are annotated. Default =\n        z matrix values.\n    :param (list|str) colorscale: heatmap colorscale.\n    :param (list) font_colors: List of two color strings: [min_text_color,\n        max_text_color] where min_text_color is applied to annotations for\n        heatmap values < (max_value - min_value)/2. If font_colors is not\n        defined, the colors are defined logically as black or white\n        depending on the heatmap's colorscale.\n    :param (bool) showscale: Display colorscale. Default = False\n    :param (bool) reversescale: Reverse colorscale. Default = False\n    :param kwargs: kwargs passed through plotly.graph_objs.Heatmap.\n        These kwargs describe other attributes about the annotated Heatmap\n        trace such as the colorscale. For more information on valid kwargs\n        call help(plotly.graph_objs.Heatmap)\n\n    Example 1: Simple annotated heatmap with default configuration\n    ```\n    import plotly.plotly as py\n    import plotly.figure_factory as FF\n\n    z = [[0.300000, 0.00000, 0.65, 0.300000],\n         [1, 0.100005, 0.45, 0.4300],\n         [0.300000, 0.00000, 0.65, 0.300000],\n         [1, 0.100005, 0.45, 0.00000]]\n\n    figure = FF.create_annotated_heatmap(z)\n    py.iplot(figure)\n    ```\n    \"\"\"\n\n    # Avoiding mutables in the call signature\n    font_colors = font_colors if font_colors is not None else []\n    validate_annotated_heatmap(z, x, y, annotation_text)\n\n    # validate colorscale\n    colorscale_validator = ColorscaleValidator()\n    colorscale = colorscale_validator.validate_coerce(colorscale)\n\n    annotations = _AnnotatedHeatmap(z, x, y, annotation_text,\n                                    colorscale, font_colors, reversescale,\n                                    **kwargs).make_annotations()\n\n    if x or y:\n        trace = dict(type='heatmap', z=z, x=x, y=y, colorscale=colorscale,\n                     showscale=showscale, reversescale=reversescale, **kwargs)\n        layout = dict(annotations=annotations,\n                      xaxis=dict(ticks='', dtick=1, side='top',\n                                 gridcolor='rgb(0, 0, 0)'),\n                      yaxis=dict(ticks='', dtick=1, ticksuffix='  '))\n    else:\n        trace = dict(type='heatmap', z=z, colorscale=colorscale,\n                     showscale=showscale, reversescale=reversescale, **kwargs)\n        layout = dict(annotations=annotations,\n                      xaxis=dict(ticks='', side='top',\n                                 gridcolor='rgb(0, 0, 0)',\n                                 showticklabels=False),\n                      yaxis=dict(ticks='', ticksuffix='  ',\n                                 showticklabels=False))\n\n    data = [trace]\n\n    return graph_objs.Figure(data=data, layout=layout)\n\n\ndef to_rgb_color_list(color_str, default):\n    if 'rgb' in color_str:\n        return [int(v) for v in color_str.strip('rgb()').split(',')]\n    elif '#' in color_str:\n        return clrs.hex_to_rgb(color_str)\n    else:\n        return default\n\n\ndef should_use_black_text(background_color):\n    return (background_color[0] * 0.299 +\n            background_color[1] * 0.587 +\n            background_color[2] * 0.114) > 186\n\n\nclass _AnnotatedHeatmap(object):\n    \"\"\"\n    Refer to TraceFactory.create_annotated_heatmap() for docstring\n    \"\"\"\n    def __init__(self, z, x, y, annotation_text, colorscale,\n                 font_colors, reversescale, **kwargs):\n\n        self.z = z\n        if x:\n            self.x = x\n        else:\n            self.x = range(len(z[0]))\n        if y:\n            self.y = y\n        else:\n            self.y = range(len(z))\n        if annotation_text is not None:\n            self.annotation_text = annotation_text\n        else:\n            self.annotation_text = self.z\n        self.colorscale = colorscale\n        self.reversescale = reversescale\n        self.font_colors = font_colors\n\n    def get_text_color(self):\n        \"\"\"\n        Get font color for annotations.\n\n        The annotated heatmap can feature two text colors: min_text_color and\n        max_text_color. The min_text_color is applied to annotations for\n        heatmap values < (max_value - min_value)/2. The user can define these\n        two colors. Otherwise the colors are defined logically as black or\n        white depending on the heatmap's colorscale.\n\n        :rtype (string, string) min_text_color, max_text_color: text\n            color for annotations for heatmap values <\n            (max_value - min_value)/2 and text color for annotations for\n            heatmap values >= (max_value - min_value)/2\n        \"\"\"\n        # Plotly colorscales ranging from a lighter shade to a darker shade\n        colorscales = ['Greys', 'Greens', 'Blues',\n                       'YIGnBu', 'YIOrRd', 'RdBu',\n                       'Picnic', 'Jet', 'Hot', 'Blackbody',\n                       'Earth', 'Electric', 'Viridis', 'Cividis']\n        # Plotly colorscales ranging from a darker shade to a lighter shade\n        colorscales_reverse = ['Reds']\n\n        white = '#FFFFFF'\n        black = '#000000'\n        if self.font_colors:\n            min_text_color = self.font_colors[0]\n            max_text_color = self.font_colors[-1]\n        elif self.colorscale in colorscales and self.reversescale:\n            min_text_color = black\n            max_text_color = white\n        elif self.colorscale in colorscales:\n            min_text_color = white\n            max_text_color = black\n        elif self.colorscale in colorscales_reverse and self.reversescale:\n            min_text_color = white\n            max_text_color = black\n        elif self.colorscale in colorscales_reverse:\n            min_text_color = black\n            max_text_color = white\n        elif isinstance(self.colorscale, list):\n\n            min_col = to_rgb_color_list(self.colorscale[0][1],\n                                        [255, 255, 255])\n            max_col = to_rgb_color_list(self.colorscale[-1][1],\n                                        [255, 255, 255])\n\n            # swap min/max colors if reverse scale\n            if self.reversescale:\n                min_col, max_col = max_col, min_col\n\n            if should_use_black_text(min_col):\n                min_text_color = black\n            else:\n                min_text_color = white\n\n            if should_use_black_text(max_col):\n                max_text_color = black\n            else:\n                max_text_color = white\n        else:\n            min_text_color = black\n            max_text_color = black\n        return min_text_color, max_text_color\n\n    def get_z_mid(self):\n        \"\"\"\n        Get the mid value of z matrix\n\n        :rtype (float) z_avg: average val from z matrix\n        \"\"\"\n        if np and isinstance(self.z, np.ndarray):\n            z_min = np.amin(self.z)\n            z_max = np.amax(self.z)\n        else:\n            z_min = min([v for row in self.z for v in row])\n            z_max = max([v for row in self.z for v in row])\n        z_mid = (z_max+z_min) / 2\n        return z_mid\n\n    def make_annotations(self):\n        \"\"\"\n        Get annotations for each cell of the heatmap with graph_objs.Annotation\n\n        :rtype (list[dict]) annotations: list of annotations for each cell of\n            the heatmap\n        \"\"\"\n        min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)\n        z_mid = _AnnotatedHeatmap.get_z_mid(self)\n        annotations = []\n        for n, row in enumerate(self.z):\n            for m, val in enumerate(row):\n                font_color = min_text_color if val < z_mid else max_text_color\n                annotations.append(\n                    graph_objs.layout.Annotation(\n                        text=str(self.annotation_text[n][m]),\n                        x=self.x[m],\n                        y=self.y[n],\n                        xref='x1',\n                        yref='y1',\n                        font=dict(color=font_color),\n                        showarrow=False))\n        return annotations\n", "path": "plotly/figure_factory/_annotated_heatmap.py"}]}