petebankhead / qupath

QuPath - Open-source bioimage analysis for research
GNU General Public License v3.0
49 stars 13 forks source link

Feature request: Adding Spatial transcriptomics support. #26

Closed JoelRV closed 5 years ago

JoelRV commented 5 years ago

Hi there,

I opened this ticket in the hopes of seeing an implementation or possible basic coding tools for viewing Spatial Transcriptomics datasets. You must be busy tending to other features right now, so allow me to briefly summarize some basic attempt I tried implementing:

-Without going into too much detail concerning the technique itself (https://spatialtranscriptomics.com/technology/), for practical purposes I can produce an json file containing the XY coords for each circular ROI that describes the RNA sampling spots on a given tissue slide (visually similar to TMA?). Using a pasted together groovy script (based on some of your previous posts), I was able to load the 33x35 spot grid unto the QuPath viewer.

Any advice or push into the right direction would be more than welcome.

Best regards, JRV

petebankhead commented 5 years ago

This sounds very interesting! I have never worked with such data, so please excuse my lack of familiarity...

From the website, I assume you need something interactive. If I understand correctly the requirements, the easiest way currently might be

This could all be scripted in Groovy. Potentially, a far nicer GUI specifically for this purpose could be scripted in Groovy or written in Java and installed as an extension, and give more control.

I'd be very keen to see this, although as you suspect I'm inundated with other things right now. For me to be able to justify giving any time to it myself in the foreseeable future, I'd need to tie it in with a research project somehow with my university hat on. But you may well not need me to do anything anyway, I think it should all be doable with a script or extension and not necessarily require any core changes.

JoelRV commented 5 years ago

Thanks for the pointer!

I'll try to cook up some basic Groovy script trying out your suggestions. I'll update this thread as I go along. Wish you the best for the academic side of your daily tasks!

JoelRV commented 5 years ago

Update: So after your feedback I came up with a first rough script version. Please note that I have no knowledge of java, so sorry for any ignorance given classes,methods and optimal coding paradigms.

Since there is no standard way to export the Spatial transcriptomics datasets, I simply encoded the data into a json file describing the EllipseROI name, xy coords and a list of gene expressions (see example text inside code snippet).

This seems to create an gene_A and gene_B entry in the Measurement Manager under the Annotations tab.

But the Measurements Maps interface remains empty,thus not allowing any visualization of that data. Indeed, it seems that the Measurement maps only works after having processed Tiles or Cell detection and using per Cell measurements.

Is it possible to use the Measurement maps to color the ROI using the data encode in an specific MeasurementList slots?

import com.google.gson.Gson
import qupath.lib.geom.Point2
import qupath.lib.objects.PathAnnotationObject
import qupath.lib.roi.PolygonROI
import qupath.lib.roi.EllipseROI
import qupath.lib.scripting.QPEx
import qupath.lib.measurements.MeasurementList
import qupath.lib.measurements.Measurement

def text = """
{
 "spots":[
  {
   "name":"1.04x0.95",
   "ellipse_param":[
    1804.52388067383,
    773.436501540091,
    463.074268872181,
    463.074268872181
   ],
   "gene_expression":[
       {"gene_A":5000,
       "gene_B":159
       }
   ]
  },
  {
   "name":"1.02x1.94",
   "ellipse_param":[
    1789.58960947385,
    1670.43387218626,
    463.074268872181,
    463.074268872181
   ],
   "gene_expression":[
       {"gene_A":800,
       "gene_B":1559
       }
   ]
  },
  {
   "name":"1x2.98",
   "ellipse_param":[
    1772.43100995701,
    2608.20758059083,
    463.074268872181,
    463.074268872181
   ],
   "gene_expression":[
       {"gene_A":8700,
       "gene_B":959
       }
   ]
  }
 ]
}
"""
//print text

// Read into a map
def map = new Gson().fromJson(text, Map)

// Extract tumor & annotations
def tumorAnnotations = map['spots']

// Convert to QuPath annotations
def annotations = []
for (annotation in tumorAnnotations) {
    def name = annotation['name']
    def vertices = annotation['ellipse_param']
    def expression = annotation['gene_expression']

    def polygon = new EllipseROI(vertices[0],vertices[1],vertices[2],vertices[3])
    def pathAnnotation = new PathAnnotationObject(polygon)
    pathAnnotation.setName(name)
    pathAnnotation.createEmptyMeasurementList()

    for (item in expression){
        //print item.keySet()
        for(gene in item.keySet()){
            def expressionValue = item[gene]
            print gene
            pathAnnotation.measurementList.addMeasurement(gene, expressionValue)
        }

    }
    //pathAnnotation.measurementList.addAllMeasurements(expression)
    print pathAnnotation.getProperties().toString()
    annotations << pathAnnotation
}

// Add to current hierarchy
QPEx.addObjects(annotations)
petebankhead commented 5 years ago

If you change PathAnnotationObject to PathDetectionObject does it work?

JoelRV commented 5 years ago

Bingo!

After loading the appropriate class and creating the PathDetectionObject instead, I got it working!

It seems to work as intended! Al the genes seem to be present in the Measurement Map window. Now I just need to find a way to make the list searchable, since a list of 20k genes is a bit cumbersome to scroll through.

Thank you very much!

NHPatterson commented 5 years ago

This is really nice.. Is it possible to make the PathDetectionObject filled rather than an outline?

Edit: Nevermind, found it in the toolbar.

petebankhead commented 5 years ago

Yes, or just press F

While I'm here, I'm tentatively considering a change to the (not especially pleasant) color map used. Any preferences? Would it be useful to have a color map that also incorporates transparency, e.g. so that low values are transparent and higher values more intensity - or does that just sound like a recipe for confusion...?

JoelRV commented 5 years ago

Hi!

Personally I don’t see the necessity. Once you find the transparency slider, I think most users will be satisfied with the options.

I would prefer a more greedy search function for the measurements. This beeing said, it only makes sense when searching a gene name amongst a list of thousands.

NHPatterson commented 5 years ago

Hi Pete,

I think for many intensity or spectral applications where this may be used, using a perceptually uniform color map is preferred and 'jet' is not one (see https://bids.github.io/colormap/ for details and multiple examples of perceptually uniform color maps). A default preference of mine would be the viridis color map which has been very popular in many publications lately. If it's not an enormous hassle, it may be worth having 4 or 5 options (including greyscale, which is also useful with spectral data).

More recently the 'cividis' colormap (https://arxiv.org/ftp/arxiv/papers/1712/1712.01662.pdf) was developed to be perceptually uniform for color blind individuals and is another strong option in my opinion.

On the transparency issue, I think that could be a very nice option. Speaking from experience comparing microscopy with imaging mass spectrometry data (the most hyperspectral of spectral data, i.e. thousands to millions of channels per image), these transparency options are useful.

Heath

petebankhead commented 5 years ago

Thanks @JoelRV and @NHPatterson I'll close this as I don't think there's more to do currently, and the improved colormaps are now included in the recent milestone releases. There's even a trick to add your own: https://twitter.com/petebankhead/status/1164504662147555329?s=20

I'd still be very interested in spatial transcriptomics support in QuPath, but don't have any relevant data to use to develop any improved functionality... and also can't really devote any time to it in the foreseeable future myself.