-
Notifications
You must be signed in to change notification settings - Fork 4
Two Channel Colocalization
[TOC]
Much of this page is adapted from the SNPFISH Colocalization Guide.
This guide will quickly detail the steps needed to perform two-channel colocalization, e.g., for odds-evens experiments or for colocalization of a single channel with spot-like autofluorescence. You can download a sample data set to play with here: Two-Channel Example Data
- First, segment and threshold your images as usual. See Worked Example.
You will need to make a YAML file with your experimental details and have this in your data directory. See the YAML Guide for more information.
In order to be precise, two-channel colocalization requires sub-pixel resolution of the centroid of the RNA spots so that colocalization can be as precise as possible. So, the next thing to do is to add a Gaussian fitting processor the image objects.
(Note, you may want to save all the commands in a script in your data directory so that you can know exactly what you did later).
- Instantiating the Gaussian Fitter. You will need to fit two channels, one corresponding to each channel to be colocalized. In this example, we will work with spots in the alexa and cy channels. The code below creates the gaussian fitting object, improc2.nodeProcs.TwoStageSpotFitProcessedData(), and adds it to all objects in your directory. The update all command actually runs these objects, which performs the fitting. (Note, this take can take several hours/overnight depending on your data-set size).
%% Add gaussian fitter
dataAdder = improc2.processing.DataAdder();
unprocessedFittedData = improc2.nodeProcs.TwoStageSpotFitProcessedData();
dataAdder.addDataToObject(unprocessedFittedData, 'alexa', 'alexa:Fitted')
dataAdder.addDataToObject(unprocessedFittedData, 'cy', 'cy:Fitted')
dataAdder.repeatForAllObjectsAndQuit();
improc2.processing.updateAll
Once your image objects have completed the gaussian fitting, you are ready to create the TwoChannelColocalizer class and add it to your image objects.
- Creating the idMap.
The idMap is a custom struct that tells the TwoChannelColocalizer your experimental design. It consists of two fields, idMap.names and idMap.channels, as shown in the example below.
idMap.channels = {'alexa', 'cy'};
idMap.names = {CHAN1 NAME, CHAN2 NAME}; % e.g., {'GRIA2evens', 'GRIA2odds'}
Ideally, instead of hard coding this, you will load it from the YAML file. See the worked example at the bottom of this script.
The idMap pairs the channels with the corresponding names of the probes tested in your experiment. Note that the first channel (CHAN1) put into the idMap serves as the reference channel against which you can check all information about colocalizations across the two channels. You can still extract data on the second channel (CHAN2), but it won't contain the spot ID or characteristics of the corresponding CHAN1 spots. This asymmetry in information will be corrected in a later version of TwoChannelColocalizer.
- Adding the TwoChannelColocalizer
Add the TwoChannelColocalizer in the same way the Gaussian fitter is added--note that it requires the idMap.
twoChanLabel = 'twoChan2'; % this is the node label--it can be whatever you want
dataAdder = improc2.processing.DataAdder();
dataAdder.addDataToObject(improc2.nodeProcs.TwoChannelColocalizer(idMap), idMap.channels, twoChanLabel);
dataAdder.repeatForAllObjectsAndQuit();
improc2.processing.updateAll();
Congratulations! You are done. You can now extract the data any way you want and analyze it as you will. For your convenience, a sample script below shows the basic steps.
%% Extract Two-channel colocalization
tools = improc2.launchImageObjectTools();
cellCounts = [];
tools.iterator.goToFirstObject
cellID = 1;
alexaAll1 = [];
cyAll1 = [];
while(tools.iterator.continueIteration)
if(tools.annotations.getValue('isGood'))
results = tools.objectHandle.getData('twoChan2');
alexa = struct2table(results.data.alexa);
alexa.cellID = ones(height(alexa),1) * cellID;
alexa.arrayNum = ones(height(alexa),1) * tools.navigator.currentArrayNum;
alexa.objNum = ones(height(alexa),1) * tools.navigator.currentObjNum;
cy = struct2table(results.data.tmr);
cy.cellID = ones(height(cy),1) * cellID;
cy.arrayNum = ones(height(cy),1) * tools.navigator.currentArrayNum;
cy.objNum = ones(height(cy),1) * tools.navigator.currentObjNum;
if isempty(alexaAll1)
alexaAll1 = alexa;
else
alexaAll1 = vertcat(alexaAll1, alexa);
end
if isempty(cyAll1)
cyAll1 = cy;
else
cyAll1 = vertcat(cyAll1, cy);
end
tools.iterator.goToNextObject;
cellID = cellID + 1;
else
tools.iterator.goToNextObject;
end
end
summary(alexaAll1)
- Using twoChannelSpotInspector
After you've completed spot colocalization, now it's time to convince yourself that the colocalizations you're detecting are real! Pick a few random cells from your dataset and note their array and object numbers. For example, in this example dataset, we're considering array 1, object 2. Navigate to your data folder and proceed:
Get the objectHandle for a cell to inspect
arrayN = 1;
objN = 2;
tools = improc2.launchImageObjectTools;
tools.navigator.tryToGoToArray(arrayN);
tools.navigator.tryToGoToObj(objN);
objectHandle = tools.objectHandle;
Now identify the TwoChannelColocalizer class node name that you want to inspect. For example, in this dataset we're using a node named 'twoChan2'.
colocNode = 'twoChan2';
TwoChannelInspector(objectHandle, colocNode)
- Use the "Up Z" and "Down Z" buttons to navigate between planes.
- Use the magnifying glass icons on the tool panel to zoom in and out
- Circles are bold when a called spot is most in focus in the viewed plane, and they are regular, or slimmer, when the spot is called but out of focus by one plane up or down.
- Circles are overlaid on the corresponding CHAN1 and CHAN2 channels when colocalized in the colocNode
In case you want to use your own method for colocalizing spots, adapt the following code to extract spot coordinates for all Gaussian-fitted spots in the channels of interest.
For each channel you run the following code, you will create a table in the working directory with spot coordinates, the amplitude/intensity of each spot, and the corresponding cell's array number, object number, and "isGood" manual annotation from thresholdGUI.
%% extract spot coordinates from Gaussian-fitted data
channel = 'alexa'; % change to the channel you want
node = [channel, ':Fitted'];
tools = improc2.launchImageObjectTools;
xCenter = [];
yCenter = [];
zPlane = [];
amps = [];
arrayNum = [];
objNum = [];
cellIsGood = [];
while(tools.iterator.continueIteration)
spotData = getFittedSpots(tools.objectHandle.getData(node));
xCenter = [xCenter, [spotData.xCenter]];
yCenter = [yCenter, [spotData.yCenter]];
zPlane = [zPlane, [spotData.zPlane]];
amps = [amps, [spotData.amplitude]];
nSpots = numel([spotData.xCenter]);
arr = ones(1, nSpots) * tools.navigator.currentArrayNum;
obj = ones(1, nSpots) * tools.navigator.currentObjNum;
isG = ones(1, nSpots) * tools.annotations.getValue('isGood');
arrayNum = [arrayNum, arr];
objNum = [objNum, obj];
cellIsGood = [cellIsGood, isG];
tools.iterator.goToNextObject
end
posDat = table(xCenter', yCenter', zPlane', amps', arrayNum', objNum', cellIsGood');
posDat.Properties.VariableNames = {'xCenter','yCenter','zPlane','amplitude','arrayNum','objNum','cellIsGood'};
fName = [channel, 'FittedSpotCoords.csv'];
write(posDat, fName);