None values in annotated heatmap

Hi all,

I’d created a heatmap using a list which can contain None values. This worked fine with a regular heatmap, None squares were not displayed.

When I converted it to an annotated heatmap using figure_factory and create_annotated_heatmap, I recieved the following error:

Traceback (most recent call last):
  File "app.py", line 326, in <module>
    shows_heatmap(),
  File "app.py", line 239, in shows_heatmap
    colorscale='Viridis')
  File "/[location]/lib/python3.6/site-packages/plotly/figure_factory/_annotated_heatmap.py", line 110, in create_annotated_heatmap
    z, x, y, annotation_text, colorscale, font_colors, reversescale, **kwargs
  File "/[location]/lib/python3.6/site-packages/plotly/figure_factory/_annotated_heatmap.py", line 292, in make_annotations
    z_mid = _AnnotatedHeatmap.get_z_mid(self)
  File "/[location]/lib/python3.6/site-packages/plotly/figure_factory/_annotated_heatmap.py", line 279, in get_z_mid
    z_min = min([v for row in self.z for v in row])
TypeError: '<' not supported between instances of 'NoneType' and 'int'

On changing the code which creates my lists, such that the None values were replaced with 0, the error didn’t occur, however these obviously now display 0 on the heatmap.

Is there a way to pass in the list containing None values, and have them be accepted? Here’s how I’m calling the function, with example not working data:

months = ['January', 'February', 'March', 'April', 'May', 'June',
              'July', 'August', 'September', 'October', 'November', 'December']
years = [2018, 2019]
shows = [[3, 1, 2, 1, 5, 6, 1, 4, 5, 1, 5, 2],[3, 3, 5, 3, 4, 8, 2, 3, None, None, None, None]]
fig = ff.create_annotated_heatmap(z=shows,
                                                   y=years,
                                                   x=months,
                                                   xgap=5,
                                                   ygap=5,
                                                   connectgaps=False,
                                                   colorscale='Viridis')

Thanks in advance!

1 Like

@gordonjb annotated heatmap doesn’t work with z-data exhibiting gaps, because of the method:
get_z_mid():
https://github.com/plotly/plotly.py/blob/master/packages/python/plotly/plotly/figure_factory/_annotated_heatmap.py#L269

Calling that method for z=shows it tries to get z_min, z_max:

z_min = min([v for row in z for v in row])

but it cannot compare None with your int data. That’s why it throws this error:

TypeError: '<' not supported between instances of 'NoneType' and 'int'

It would have worked if the method had been defined as follows:

def get_z_mid(self):
   """
   Get the mid value of z matrix
   :rtype (float) z_avg: average val from z matrix
   """
   if np and isinstance(self.z, np.ndarray):
       z_min = np.nanmin(self.z)
       z_max = np.nanmax(self.z)
   else:
       z_min = min([v for row in self.z for v in row if v is not None])
       z_max = max([v for row in self.z for v in row if v is not None])
   z_mid = (z_max + z_min) / 2
   return z_mid
1 Like

Thank you for pointing that out! I also had to make a similar change to make_annotations to get it to work:

def make_annotations(self):
    """
    Get annotations for each cell of the heatmap with graph_objs.Annotation

    :rtype (list[dict]) annotations: list of annotations for each cell of
        the heatmap
    """
    min_text_color, max_text_color = _AnnotatedHeatmap.get_text_color(self)
    z_mid = _AnnotatedHeatmap.get_z_mid(self)
    annotations = []
    for n, row in enumerate(self.z):
        for m, val in enumerate(row):
            font_color = min_text_color if (val is None or val < z_mid) else max_text_color
            annotations.append(
                graph_objs.layout.Annotation(
                    text=str(self.annotation_text[n][m]) if val is not None else "",
                    x=self.x[m],
                    y=self.y[n],
                    xref="x1",
                    yref="y1",
                    font=dict(color=font_color),
                    showarrow=False,
                )
            )
    return annotations

but with a local copy of _annotated_heatmap this is working now. I’ll try remember to suggest the change.

Thanks again!

1 Like

It would be great if this was alredy changed in the latest version, what a pity…