1

I want to make a heatmap using seaborn. I have a 1920x1080 2D array that contains saliency values of each pixel of an image from 0-1 (0=lowest saliency-blue color, 1=highest saliency-red color). I have divided my image into smaller grids of 80x90 pixels. I am getting the image below:

enter image description here

So far so good. What I want to do next is to create a seaborn heatmap, so that each grid is averaged and represented by only one color (with blue grids representing areas of low saliency and warmer grids representing areas of high saliency), like below:

enter image description here

However, using this code:

import numpy as np

plt.figure(figsize= (16,9)) 
xticklabels=range(0,1920,80)
yticklabels=range(0,1080,90)
xticks[80,160,240,320,400,480,560,640,720,800,880,960,1040,1120,1200,1280,1360,1440,1520,1600,1680,1760,1840,1920]
yticks=[90,180,270,360,450,540,630,720,810,900,990,1080]

normalized_saliency_map=np.random.random((1080,1920))

ax=sns.heatmap(normalized_saliency_map, 
               cmap='jet',
               linewidth=0.5,
               xticklabels = xticklabels, 
               yticklabels = yticklabels)
ax.set_xticks(xticks)
ax.set_yticks(yticks)
plt.title(f'Image: {i}')
plt.show()

I am getting this empty plot:

enter image description here If I comment out ax.set_xticks(xticks) and ax.set_yticks(yticks), I am getting this:

enter image description here

What am I missing here?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Phoenix
  • 73
  • 6

1 Answers1

1

Main Array

  • Remove linewidth
  • Add set_xticklabels and set_yticklabels
# test data
np.random.seed(365)
data = np.random.random((1080,1920))

ax = sns.heatmap(data, cmap='jet')
ax.set_xticks(xticks)  # this is only the tick location, not the label
ax.set_xticklabels(xticks)  # this adds the labels, after setting the ticks
ax.set_yticks(yticks)
ax.set_yticklabels(yticks)

ax.invert_yaxis()  # use if desired to swap the direction of the y-axis values
ax.grid(color='k')

plt.show()

enter image description here

Divide the Array

  • I used the function in this answer to chunk the data into an array (288, 90, 80)
# using function from other answer
chunked = blockshaped(data, 90, 80)

# get the means of each chunk and then reshape
means = np.array([v.mean() for v in chunked]).reshape(12, 24)

# plot the chunks
fig, ax = plt.subplots(figsize= (16,9)) 

p = sns.heatmap(means, cmap='jet', ax=ax)

p.set_xticks(range(25))
p.set_xticklabels([0] + xticks)
p.set_yticks(range(13))
p.set_yticklabels([0] + yticks)

p.invert_yaxis()
p.grid(color='k')

plt.show()

enter image description here

blockshaped

  • Here's the function from the other answer for reshapeding the array
def blockshaped(arr, nrows, ncols):
    """
    Return an array of shape (n, nrows, ncols) where
    n * nrows * ncols = arr.size

    If arr is a 2D array, the returned array should look like n subblocks with
    each subblock preserving the "physical" layout of arr.
    """
    h, w = arr.shape
    assert h % nrows == 0, f"{h} rows is not evenly divisible by {nrows}"
    assert w % ncols == 0, f"{w} cols is not evenly divisible by {ncols}"
    return (arr.reshape(h//nrows, nrows, -1, ncols)
               .swapaxes(1,2)
               .reshape(-1, nrows, ncols))
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158