Tutorial 2: Pixel map integration
Welcome to the second part of our planktonpy tutorial. In this part, we will use plankton’s functionality to explore the hippocampal data set from tutorial 1. We will attempt to get a general overview of the data and do some basic quality control. The we will try to find spatial patterns in our data set, which we will observe more closely and treat statistically in tutorial 3.
To be able to explore the expression patterns at full depth, we will make use of all data modalities available. It the case of Xiaoyan Qian’s ISS experiment, this includes:
In-situ sequencing-derived spatial expression data (as used in tutorial 1)
Transcription data from a single-cell RNA sequencing experiment
Histological images that have been segmented into a pixel-based cell map
During this tutorial, we will attempt to integrate these different modalities and use them for quality control and to provide a context for our spatial observations.
Pixel maps as a plotting background
Many spot-based spatially resolved transcriptomics studies produce histological images to document the anatomy of sample slides. They are comparatively cheap to make and provide a great reference for the detected transcriptomes, all the way from experimental quality control to visualizing and contextualizing final results.
Plankton offers a PixelMaps class to integrate pixel-based spatial information (like histology stainings or tissue maps) with the spot-based data set propper. It allows for easy plotting, cropping, rescaling and data sampling.
To follow along, start an ipython server and open the notebook tutorials/exploratory.ipynb and run the first three cells to download the ISS coordinates, a DAPI background stain and a cell-map data set.
DAPI stain is loaded into the variable dapi_data as a 2d array:
plt.imshow(dapi_data)
Unfortunately, the resolution of the DAPI stain is not the same as the ISS coordinates from last tutorial. This is one of the use cases for the plankton.PixelMap wrapper: It accepts a scaling parameter to siplify data integration. In our case, the DAPI-image’s um-per-pixel value is 0.2694, which we need to use as an upscaling parameter.
dapi_map = pl.PixelMap(dapi_data, upscale=0.2694)
dapi_map.imshow(cmap='Greys')
as you can see, the scale now fits the coordinate data of tutorial 1, and we’re set to create a SpatialData set once again, this time providing pixel data as a plotting background. Note that, when integated into the data set, the PixelMaps are transformed alongside the sdata object (e.g. during cropping):
sdata=pl.SpatialData(spot_data.Gene,
spot_data.x,
spot_data.y,
pixel_maps={'DAPI':dapi_map}
)
plt.title('Cropped data set with DAPI background')
sdata.spatial[4000:5000,500:1000].scatter(marker='x')
This immediately provides us with a first basic way of quality control: We can observe that two modalities of spot and pixel-based data integrate, with both showing spatially co-occurring signal.
Parsing pixel map data
Next to the DAPI stain, Qian et al provide a cell segmentation map, which was downloaded and saved into the variable cell_data. It is an integer-based 2d array with a zonal indexing of cells areas (using 0 as background value). It is already in scale for our ISS data set, so no resolution adjustment is necessary:
cell_map = pl.PixelMap(cell_data)
#add the cell map to sdata
sdata.pixel_maps['cells']=cell_map
plt.colorbar()
cell_map.imshow(cmap='nipy_spectral')
We can use the PixelMap.get_value method to acquire the pixel map data at a certain position in data-set coordinates. For our ISS data, this allows us to parse the cell map and assign every molecule the id of the cell it occurs in:
sdata['cell_id'] = cell_map.get_value(sdata.x,
sdata.y,
padding_value=0 #assigned to off-map points
)
sdata
| g | x | y | gene_id | cell_id | |
|---|---|---|---|---|---|
| 0 | Cxcl14 | 110 | 5457 | 24 | 51 |
| 1 | Plp1 | 0 | 4735 | 56 | 0 |
| 2 | Plp1 | 0 | 4725 | 56 | 0 |
| 3 | Id2 | 0 | 4478 | 35 | 0 |
| 4 | Enpp2 | 0 | 4455 | 26 | 0 |
| ... | ... | ... | ... | ... | ... |
| 72331 | Npy | 7305 | 1257 | 45 | 3453 |
| 72332 | Npy | 7331 | 1360 | 45 | 0 |
| 72333 | Npy | 7425 | 1294 | 45 | 0 |
| 72334 | Npy | 7467 | 1287 | 45 | 3474 |
| 72335 | Npy | 7492 | 1268 | 45 | 0 |
This provides us with another opportunity for quality control: We can determine the ratio of molecules that were recovered within cell boundaries versus the extracellular matrix:
intra_extra_ratio = (sdata.cell!=0).mean()
print(f'{int(100*intra_extra_ratio)}% of cells are detected within molecule boundaries.')
'61% of molecules are detected within cell boundaries.'
You now have mastered the basics of PixelMap integration in the plankton framework! In the next setp, we will cover the integration of external sequencing data using scanpy data frames.