3

Just for fun I'm trying to code a mouse tracking script, I have the basic part working, but I'm having absolutely no luck with heatmaps.

My initial code was to save an image via PIL (just to check it was working), which was fine, but obviously it was only single dots. I then tried to implement my own heat map, but found that it'd take over half a year of processing for something really basic, so that wasn't going to work either.

I've been trying different examples of matplotlib, but I've just realised "heat map" means something different in this case.

enter image description here

It's not not working, but it's also definitely not the result I was hoping to see. I'm wondering if anyone knows how I'd actually go about getting the other type of heatmap, where you get the blobs of heat? I've been googling a bunch of terms but it seems to lead back to the same 3 or so SO questions.

The data is stored in a dictionary of {(x, y): frequency}, so to get the result above I used this code (matplotlib part got from Plotting a 2D heatmap with Matplotlib):

import matplotlib.pyplot as plt

resolution = (1920, 1080)

total = []
for y in range(resolution[1]):
    row = []
    for x in range(resolution[0]):
        try:
            row.append(data[(x, y)])
        except KeyError:
            row.append(0)
    total.append(row)

plt.imshow(total, cmap='hot', interpolation='nearest')
plt.show()

The speed of that doesn't matter so much as it'll be done separately to the tracking, I'd just like something that'd initially work.

Edit: Just to clear it up a little (apologies if it wasn't clear), something like this is what I'd like: enter image description here

Community
  • 1
  • 1
Peter
  • 3,186
  • 3
  • 26
  • 59
  • That code should work, as long as your data dictionary is indeed formatted as you expect. It seems to me that you are just plotting zeros, so I would suggest looking at what is happening in your try/except statement – Sven Rusch Feb 18 '17 at 14:17
  • Well if you look at the higher resolution it does work, but only plots the individual pixels. I was after the blob style heatmap stuff – Peter Feb 18 '17 at 14:20

1 Answers1

2

My solution for plotting such heat maps is as follows. It's easy to fill the 2D numpy array with your data taking data[(x, y)], and then use the plot function. Note that you can use any colormap you like, I use the one presented in the code. The sample should work out of the box.

The "blobby" look can be achieved using the gaussian blur. You can adjust sigma to make it sharper or smoother.

import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np

import scipy.ndimage.filters as filters


def plot(data, title, save_path):
    colors = [(0, 0, 1), (0, 1, 1), (0, 1, 0.75), (0, 1, 0), (0.75, 1, 0),
              (1, 1, 0), (1, 0.8, 0), (1, 0.7, 0), (1, 0, 0)]

    cm = LinearSegmentedColormap.from_list('sample', colors)

    plt.imshow(data, cmap=cm)
    plt.colorbar()
    plt.title(title)
    plt.savefig(save_path)
    plt.close()

if __name__ == "__main__":
    w = 640
    h = 480

    data = np.zeros(h * w)
    data = data.reshape((h, w))

    # Create a sharp square peak, just for example
    for x in range(300, 340):
        for y in range(300, 340):
            data[x][y] = 100

    # Smooth it to create a "blobby" look
    data = filters.gaussian_filter(data, sigma=15)

    plot(data, 'Sample plot', 'sample.jpg')

P.S. cmap='jet' also gives the desired look out of the box.

Dmitry Shurov
  • 434
  • 6
  • 16
  • Thanks, would this apply to the style of heatmap I'm aiming for though? Had a quick look but it all appears to be coloured :) – Peter Feb 18 '17 at 14:22
  • Sure, just use `cmap='hot'` instead of my custom color map. – Dmitry Shurov Feb 18 '17 at 14:24
  • Just seen your edit. Well, my custom color map is really close to what you need, except that I color zero-density areas with white. I think you may adjust the color map to something like: `colors = [(0, 0, 1), (0, 1, 1), (0, 1, 0.75), (0, 1, 0), (0.75, 1, 0), (1, 1, 0), (1, 0.8, 0), (1, 0.7, 0), (1, 0.0, 0)]`. Just play with it :) – Dmitry Shurov Feb 18 '17 at 14:32
  • And finally I edited my answer to help you get the "blobby" look using gaussian blur, just like in the sample image. – Dmitry Shurov Feb 18 '17 at 14:43
  • Alright thanks, annoyingly the internet has gone down again so I'll check it out shortly :) – Peter Feb 18 '17 at 14:54
  • Just took me forever and about 6 different modules to install scipy haha, but thanks a bunch, the result looks decent. I'm working soon though so I'll test it out on my code once I'm back – Peter Feb 18 '17 at 15:55
  • 1
    Another option is using OpenCV's `cv2.applyColorMap()` function. – Jeru Luke Feb 18 '17 at 17:24
  • 1
    By the way, I just realized that `cmap='jet'` also gives the desired look out of the box. – Dmitry Shurov Feb 18 '17 at 18:06