Creating tumor margins annotations

I am running the script for creating tumor margins annotations on V0.2.0m2. It runs great on single images, but I get an “please select an annotation object” error when I run it as a project. I tried adding “selectAnnotations();” before the script, but that doesn’t seem to work. Could you help me with this? Thanks!

I think that script requires one annotation to be selected for the expansion to work off of. Otherwise you will need to find some other way to select an annotation to target, but generally you only want one. The total tissue annotation would normally be used only as a constraint for the selected annotation, for example.

There are a set of scripts that demonstrate selecting things posted elsewhere, but on my phone atm. Will link it later if you still want.

So not 100% sure if you are referring to this script of Pete’s or one of the other variants here, but essentially you will run into a problem at:

// Get annotation & detections
def annotations = getAnnotationObjects()
def selected = getSelectedObject()
if (selected == null || !selected.isAnnotation()) {
    print 'Please select an annotation object!'

getSelectedObject() returns a single object, and the rest of the script is based off of only being passed a single object. selectAnnotationObjects() would return a list of objects, even if there is only one object. If there is only one object, your best bet is probably something like replacing that selected line with:

selected = annotations[0]

Now selected is a single annotation object, and the rest of the script should proceed. Again, this assumes that you only have one annotation object in the images you are running this script on. If you have multiple objects, it will get more complicated.

I want to calculate number of CD8 positive cells per mm2 in the tumor core and the margins (250um on each side).
I am running Pete’s script modified by Thomas Kilvaer. However I decided not to run the script as project. I am doing the simple tissue detection, drawing the polygon for the area where I want the margin to be drawn and running the margins script for each case individually since I have to delete the simple tissue detection before running positive cell detection anyway. I’ll just run the stain deconvolution, positive tissue detection and export annotations as a project after.
So I didn’t try replacing the selected line. But I hadn’t seen the reduced annotations link which was useful too. So thanks!

Sounds good. If you ever do want to run for a project, you would probably want to do something like classify the hand drawn part, and then select the one Tumor object as part of the script with a findAll statement after the getAnnotationObjects.

I know it is an old post, but I am also trying to measure CD8+ cells in TMA cores and have been succesfull in positive cell detection, but the output is only in % of detections. The line of Num Positive per mmˆ2 says: Nan. How can I define the area of the core, is it possible?

Which version are you running?

And if you want the num positive per mm^2, it might be easier to get it by running simple tissue detection on the cores, in case of areas with a lot of whitespace. I suspect there is a getArea() function for the TMA core, but it probably won’t always be meaningful.
*Ah, if you are cycling through the cores, you can use it.getROI().getArea(), which will give you the area in pixels. You would need to multiple that by the pixel size to convert units into square millimeters.

Also, if you or anyone else has a shareable TMA, it would be great to have a sample for my “convert a TMA into a heatmap” script.


What do you mean by simple tissue detection?

When I use Fast Cell Counts I get good results in %, but still NaN in the Number of positive cells / mmˆ2

It looks like you might be picking up a bit of the [necrotic, deposit, cartilage]? as positive as well, which you might be able to separate out using a classifier, or “positive cell detection.”

If, before you run any kind of cell detection, you use Analyze->Preprocessing->Simple tissue detection, you can use the resulting annotation to get an area measurement for the tissue in the core. Using it can be a bit more tricky, as you will need either a script or a separate export to make use of the area.

I don’t have M4 installed on this computer, but I don’t think the TMA stuff has changed. A simple script to get the TMA area might be:

def server = getCurrentServer()
def cal = server.getPixelCalibration()
pixelSize =  cal.getPixelWidthMicrons()

hierarchy = getCurrentHierarchy()
cores = hierarchy.getTMAGrid().getTMACoreList()
cores.each {
it.getMeasurementList().putMeasurement("Area", it.getROI().getArea()*pixelSize*pixelSize)

I also might have made any number of errors there that I won’t be able to test 'till later.

If it works, it won’t calculate the density for you, but it should give you the information you need to calculate the density. Though, I would be careful of any calculation made this way, since a TMA that was “half missing” would automatically have half the cell density of a full piece of similar tissue. Or, in other words, unless 100% of your TMA cores completely fill the TMA ellipse, it isn’t a very good measurement.

To get the density you will need a single annotation for every core, otherwise only the percentage positive will be given (as it wouldn’t be clear what area to normalise to).

See also

1 Like

Ah, I forgot, if I ever knew, that it was automatic! So yes, just use that Simple Tissue Detection, and leave Single annotation checked. Probably will want to run your cell detection by selecting Annotations rather than TMA cores after that (I’m pretty sure you will have to run the Tissue Detection first).
Some more information on simple tissue detection here.

Thanks so much. My TMAs mostly tumor only, and I am not worried about blank spaces. Now I see what you mean by simple tissue detection, I have used it in the past.

@Research_Associate each of my TMA cores is a different case, so I have to run cell detection by Cores and not annotations, is that correct?

By annotations, otherwise the tissue annotation objects will be deleted.

QuPath checks to see if the core contains a single annotation with positive/negative cells inside and nothing else, and if so displays the density measurement for that core. If the core contains multiple annotations, or no annotations, or cells outside of annotations then it will not.

The supplementary material of my original Scientific Reports QuPath paper (here) includes the scripts I applied for CD3/CD8 analysis and it’s described step-by-step in the wiki link I posted above.

1 Like