Heat maps for citizen science image annotations

Last summer saw the MoEDAL Collaboration launch Monopole Quest at the Royal Society Summer Science Exhibition. Built with Zooniverse's Panoptes system, volunteers can help analyse scans from MoEDAL's Nuclear Track Detector (NTD) plastic by looking for "blobs" and "rings".

In analysing the first results from the project, I've had some fun with using matplotlib's graphics libraries to get a feel for what's been classified and how. One example is using a heat map to see how well volunteers identified the centre of a blob in a given scan image.

An example image from a MoEDAL Nuclear Track Detector scan showing a clear example of a "blob".

The example above is a 64x65 pixel scan, scaled up by a factor 6, with one fairly-well defined "blob" in it. It's relatively straightforward to add a scatterplot of the volunteers' blob centres onto this image with the scatter method:

plt.scatter(blob_xs, blob_ys, marker='x', color='red')

which produces this sort of thing:

However, it's just a little bit messy - and gets messier as more classifications are added. In this GitHub repository, the script make_image_heatmap.py goes through the following steps to create a heat map of the blob centres based on the volunteers' classifcations:

1) Read in the image: the matplotlib.image library lets you read in a PNG file as a NumPy array. This can then be added to the figure and displayed with axes.

2) Read in the annotation information: the subject annotation information for each image relevant to this analysis is the volunteer's placement and radius of the blob - x, y, and r. In the example repository this has been extracted from the Panoptes classification dump into a CSV file, which is read by the script and then put into three Python lists.

3) Create the heat map with a 2D histogram: the numpy.histogram2d function allows to create the heat map using the x and y lists. The bins and range can be set to match the image properties.

4) Scale up the heat map to match the scaled-up image: scipy.ndimage.interpolation does a nice job of scaling images (which are NumPy arrays).

5) Superimpose the heat map onto the original scan: by setting the alpha value of the heat map image when we imshow to a value less than 1, the original image shows through. This allows us to compare the two

6) Add a colour bar: so that we know what the heat map colours mean.

Running the script produces the following image:

The heat map displaying the volunteers' interpretations of where the centre of the blob is.

As you can see, most of the annotations do indeed appear to be in the centre of the blob - and the heat map helps show where with a little more clarity and style. Of course, this is a trivial example - there is only one (very circular) blob and it is pretty obvious where it is. This makes this particular scan useful as a kind of calibration subject. For more complicated images, a heat map might provide a way of presenting annotation information more clearly than a simple scatter plot - hopefully the code provided will save you a few Google/StackOverflow queries!