Identifying dense groups of cells, or specific microenvironment clusters is an increasingly important area of image analysis, and one that I wanted to open up a discussion on as far as automating ways of finding these types of areas.
I started with the simplest option for an earlier project, the Delaunay cluster features, which does a nice job of finding “clusters” of cells when there are only two classes of cells, or no classes. I could fairly easily find clusters of a certain size by removing all cells except for those of the class I was interested in, and then running the Delaunay analysis on each class in turn. Unfortunately, that also picked up long strings of cells, as the only requirement for a cluster was that any two cells of the cluster be within X distance of each other. In other words, it was not the measure of density I was looking for.
Aside: The reason I needed to remove every other cell class was that any two cells of a class created a line between them, a line which could not then be crossed by another class. So, if I were interested in clusters of T cells in a tumor environment, and there were more tumor cells than T-cells, the chances were I would never pick up the clusters I was interested in.
See this post about nearest neighbors for a visual demonstration of the problem: QuPath Script: Nearest Neighbors
That led to a second attempt, included here, where I built off of Pete’s script here.
Script included in second post.
The new script creates a heatmap of each class, and then create isolines based on some threshold that could be turned into annotation objects.
Hopefully a clearer explanation in individual steps.
- Create one blank 2D array of sufficient size to represent the whole image, for each class (Negative is excluded by default, others could be as well) of interest.
- Cycle through all cells and add a point to the array of the appropriate class at the XY coordinates of that cell.
- Based on some distance, expand each of those points into a circle. If the distance is large enough, these circles will start to overlap.
- Create isolines at a certain value. IE, if 4 or more cells are within “distance” of a certain point, that point will be included within an annotation.
- Remove all annotations that contain fewer than a set number of cells. For whole tissue images, someone might be interested only in clusters of over 100 cells, while someone working with high powered confocal images might be interested in a cluster of 5-10 cells.
- Finish with the annotations inserted into the hierarchy so that the user can look at what other cell types are included within that annotation.
If you are only interested in one class, there is a line in the script to edit the classes that are or are not analyzed (defaults to “not Negative”). There is a smoothing value at the top of the script that can be adjusted.
Brightfield, DAB, positive cell detection.
Specifically looking for clusters over 30 cells, in this case. With Positive cell detection, each hotspot annotation comes with positive and negative counts, percent positive, and the area and positive cell density!
With the heatmap checkbox selected, you can also see the actual heatmap used to generate the annotations for the current run, which can help you better choose your density threshold.
Here is another example using the same image Pete used for his multiplex classification tutorial. With multiple classes of cells, the results become more interesting and useful.
Looking for relatively smaller clusters this time, I only found three classes with sufficient density (Teal CK, Red PDL1, Green PD1). The script currently looks for final classes, not single channel classes, so some of the areas that look like they should be within a hotspot are double or triple positive with one of the other five channels.
Selecting one of the red PDL1 hotspots in the top left, I can quickly see that the other main classes within the hotspot are PDL1+PD1 positive and PDL1+CD8 positive (and negative).
Here is the PDL1 heatmap, for reference. Each circle has a radius of 20um. That is where the “Distance between cells” measurement is used to build the map.
Increasing the Density to 4 removes some of the less tightly grouped hotspots and tightens the boundaries on the remaining hotspots.
I can use the heatmap to choose a Density value of 4 by looking at the pixel “values” under the mouse cursor on the ImageJ bar.
This script, and Pete’s that was linked earlier, are two ways of handling hotspot/cluster detection. The original script created a single circle around a hotspot, and I first expanded that script to find any locations where the density was “sufficiently high” and created circles at those points. That created a rather large number of circles, and rather than trying to fix that, I realized the circles could be built up like a topographical map (not a new idea, but new to me at the time).
From what I have seen of use cases, though, the power of being able to do this in an automated fashion relates to the meaningfulness of information that can be extracted from each hotspot. I feel that that information is more meaningful when the annotation the information is based on traces the biologically important regions.
I am interested in other ideas concerning what hotspots or clusters could mean, or other ways of finding groups of objects. This method does not capture any information about the actual structure of the microenvironment, with each class being considered separately. One possibility for capturing this type of information for a multiplex analysis might be to create isolines per marker, and use the intersection of the annotations to keep overlapping regions of certain types (T-cell -memory + Macrophage+CK) or (+memory+stroma). Another possibility with the new classification system in M9 might be to try to add sub-classes based on nearby neighbors (Tumor cells with >N T-cells within 20um) and create hotspots where the classification of the cells is based on the local environment. Combining this script with the nearest neighbors counts could open up some interesting options.
Open to ideas, hoping to get some feedback!