Multiple images may be attached to the Giotto object. Spatial data can be overlaid upon these images which may then be used for downstream analyses. While Giotto attempts to automate the addition and alignment of images as much as possible, manual adjustments may sometimes be necessary. This tutorial will be covering both automatic and manual adjustment.
The examples in this tutorial will be worked using Visium"s normal human prostate FFPE dataset for both the Visium (automatic) and manual adjustment workflows. A manual download of this data is required; please see Visium Directory Structure Details below.
For an example of working with high definition images that may require ROI alignment and or stitching, please see the Nanostring CosMx lung data analysis.
# Ensure Giotto Suite is installed
if(!"Giotto" %in% installed.packages()) {
pak::pkg_install("drieslab/Giotto")
}
library(Giotto)
# Ensure Giotto Data is installed
if(!"GiottoData" %in% installed.packages()) {
pak::pkg_install("drieslab/GiottoData")
}
library(GiottoData)
# Ensure the Python environment for Giotto has been installed
genv_exists <- checkGiottoEnvironment()
if(!genv_exists){
# The following command need only be run once to install the Giotto environment
installGiottoEnvironment()
}
Giotto currently supports two types of image objects. For most purposes, images are loaded in using terra and are then placed into giottoLargeImage objects. giottoLargeImage objects only load in sampled subsets of the original image that are needed to represent the image, increasing efficiency for analysis of very high-resolution images.
Alternatively, smaller images are loaded in using the magick package and are then placed into giottoImage objects. This offers direct access to the powerful image processing functionality in the magick package among other Giotto functions for analysis and viewing. giottoLargeImage objects can be downsampled into giottoImage objects when necessary through use of the convertGiottoLargeImageToMG() function.
More about the giottoImage container
giottoImages are S4 class objects with slots containing the image itself and the metadata necessary to plot it properly. The magick package allows easy access to image processing functions as well as the ability to access images through pointers, so the images are only loaded into memory when needed.
Please note that as a result of using pointers to access the image, giottoImages will not be saved between sessions, since the pointer will die after a given R session is closed. However, the information used to create the image will be retained within the giottoObject in the images slot, as described below.
When incorporated into a giottoObject, giottoImages are added into the images slot of the giottoObject. The images slot is organized as a list() so multiple giottoImages may be added and then referred to individually using the name which they have been given.
giottoImage Structure
*Note that minmax refers to the relevant values of the associated spatial locations rather than those of the image. These values are given either by providing spatial locations directly when calling createGiottoImage() or in later steps that involve a giottoObjects with associated spatial locations.
For maximum flexibility, Giotto plots images and spatial data on different layers that are largely independent of each other. The spatial data is plotted first, essentially serving as an anchor (xmin, xmax, ymin, ymax). The image, no matter its actual dimensions or resolution, is then stretched to fit on the plot according to accompanying metadata (xmin_adj, xmax_adj, ymin_adj, ymax_adj) which can be edited by the user.
Calling the giottoImage by itself will display its class and name, followed the values that occupy its minmax, boundary adjustment, scale_factor, and resolution slots. The actual image boundaries are displayed as spatial values, which detail the points to which the image"s edges will be stretched.
Most spatial datasets currently generate spatial locations based on how they map onto an original image. Although this brief explanation is somewhat simplified, Giotto"s automatic alignment works as follows:
For instance, assume a giottoImage object named GImage has already been created:
GImage
## R TERMINAL OUTPUT:
#
# An object of class " giottoImage " with name image
#
# Min and max values are:
# Max on x-axis: 23520
# Min on x-axis: 5066
# Max on y-axis: -3682
# Min on y-axis: -23148
#
# Boundary adjustment are:
# Max adjustment on x-axis: 3949.001
# Min adjustment on x-axis: 5066
# Max adjustment on y-axis: 3682
# Min adjustment on y-axis: 2082.277
#
# Boundaries are:
# Image x-axis max boundary: 27469
# Image x-axis min boundary: 0
# Image y-axis max boundary: 0
# Image y-axis min boundary: -25230.28
#
# Scale factor:
# x y
# 0.07280935 0.07280935
#
# Resolution:
# x y
# 13.7345 13.7345
#
# File Path:
# [1] "/path/to/directory/tissue_image.png"
Further intuition for defining these parameters in this way is detailed within the Why this inversion is necessary dropdown text beneath Standard workflow.
Assembly of Giotto object as well as the reading in and alignment of the tissue staining image from the Visium spatial subdirectory is done automatically using createGiottoVisiumObject().
Note that in order to run the following code, the Output Files “Feature barcode matrix (raw)” and “Spatial imaging data” from the dataset must be downloaded and extracted into a structured Visium directory.
Visium Directory Structure Details
Here, details on how to structure the Visium Directory for creating a Giotto object using createGiottoVisiumObject() for the purposes of this tutorial will be shown. Nonetheless, this procedure is standard practice for using Giotto with Visium Data.
First create a new directory. This will be the Visium Directory. Then, open a terminal within that directory, and enter the following commands:
wget https://cf.10xgenomics.com/samples/spatial-exp/1.3.0/Visium_FFPE_Human_Normal_Prostate/Visium_FFPE_Human_Normal_Prostate_raw_feature_bc_matrix.tar.gz
tar -xzvf Visium_FFPE_Human_Normal_Prostate_raw_feature_bc_matrix.tar.gz
wget https://cf.10xgenomics.com/samples/spatial-exp/1.3.0/Visium_FFPE_Human_Normal_Prostate/Visium_FFPE_Human_Normal_Prostate_spatial.tar.gz
tar -xzvf Visium_FFPE_Human_Normal_Prostate_spatial.tar.gz
This will create two subdirectories within the Visium Directory, titled “raw_feature_bc_matrix” and “spatial”. These subdirectories will contain barcode and expression information, or images and scaling information, respectively. Now, the Visium Directory may be inputted to createGiottoVisiumObject()!
A giotto object using either the hires or lowres image will be loaded depending on whether "tissue_hires_image.png" or “tissue_lowres_image.png” is provided to the png_name argument. In this example, the hires image will be plotted.
library(Giotto)
library(GiottoData)
data_path <- "/path/to/data/"
results_folder <- "/path/to/results/"
# Optional: Specify a path to a Python executable within a conda or miniconda
# environment. If set to NULL (default), the Python executable within the previously
# installed Giotto environment will be used.
python_path <- NULL # alternatively, "/local/python/path/python" if desired.
# Optional: Set Giotto instructions
instructions <- createGiottoInstructions(save_plot = TRUE,
show_plot = FALSE,
return_plot = FALSE,
save_dir = results_folder,
python_path = python_path)
# Create a Giotto Object using Visium Data
FFPE_prostate <- createGiottoVisiumObject(expr_data = "raw",
visium_dir = data_path,
png_name = "tissue_hires_image.png",
instructions = instructions)
# visualize spots that are in tissue
spatPlot2D(FFPE_prostate,
show_image = TRUE,
cell_color = "in_tissue",
save_param = list(save_name = "high_res_IT"))
Before beginning, it is important to acknowledge that differences may exist in the conventions for defining coordinates within images and plots. As a result, it is often required to make the spatial location y values negative. This inversion is necessary for the spatial locations to appear in the same orientation as the image. This transformation of the spatial locations is automatically done for Visium datasets during createGiottoVisiumObject(). In the standard workflow, it is important to determine if this is necessary for the data at hand.
Why this inversion is necessary
Image Coordinates vs Plotting Coordinates By convention, the origin of image coordinates is defined in the upper left, and coordinates increase rightward (x coordinate) and downward (y coordinate). Many spatial methods inherit this convention when generating spatial location data. However, Giotto plots with the coordinates originating from the lower left. Thus, without inversion of the y coordinates, the spatial locations are displayed as vertically flipped compared to how they are intended to be seen.
The fix for this is to multiply all the Y-values in spatial locations by -1, inverting them. This may be done prior to creation of the giotto object by multiplying the y values within the spatial location matrix by -1. If the giotto object has already been created, yet the spatial data still needs inversion, running the following commands will invert the y coordinates.
Here, my_gobject refers to the giottoObject and my_spatlocs refers to the name of the spatial locations to which the image will be aligned.
# Retrieve original spatial location data as a spatLocObj
spatlocs <- getSpatialLocations(gobject = FFPE_prostate,
output = "spatLocsObj")
spatlocs[]$sdimy <- -spatlocs[]$sdimy # Note the negative sign operator for inversion
# Overwrite the original spatial locations with the inverted ones
my_gobject <- setSpatialLocations(gobject = FFPE_prostate,
x = spatlocs)
giottoImages are created using the createGiottoImage() function. This function requires a magick-compatible image (eg. jpg, tiff, png) to be provided to the mg_object argument as either a filepath or a magick object.
If automatic image alignment is desired, the scale_factor parameter is required, which scales the spatial locations to the image. This parameter is required since spatial locations do not contain information about the size of the image is past the spatial xmax and ymin values. Those two image bounds are instead inferred by scaling up the current image dimensions to those of the spatial locations.
For Visium datasets, scaling information is available in the scalefactors_json.json file found within the spatial subdirectory.
scalefactors_json.json for this dataset:
"tissue_hires_scalef": 0.072809346, "tissue_lowres_scalef": 0.021842804, "fiducial_diameter_fullres": 304.63145798068047, "spot_diameter_fullres": 188.58137874994503} {
Providing the appropriate factor to the scale_factor parameter will result in automatic alignment.
lowResPath <- paste0(data_path, "spatial/tissue_lowres_image.png")
lowResG_img <- createGiottoImage(gobject = FFPE_prostate,
mg_object = lowResPath,
name = "low_res",
scale_factor = 0.021842804)
Alignment values:
lowResG_img
" giottoImage " with name low_res
An object of class
:
Min and max values are Max on x-axis: 23520
-axis: 5066
Min on x-axis: -3682
Max on y-axis: -23148
Min on y
:
Boundary adjustment are Max adjustment on x-axis: 3949.001
-axis: 5066
Min adjustment on x-axis: 3682
Max adjustment on y-axis: 2077.699
Min adjustment on y
:
Boundaries are Image x-axis max boundary: 27469
-axis min boundary: 0
Image x-axis max boundary: 4.547474e-13
Image y-axis min boundary: -25225.7
Image y
:
Scale factor x y
0.0218428 0.0218428
:
Resolution x y
45.78167 45.78167
:
File Path [1] "~/Visium_FFPE_Human_Normal_Prostate/spatial/tissue_lowres_image.png"
Without spatial locations
lowResG_img_no_locs <- createGiottoImage(mg_object = lowResPath,
name = "low_res_no_locs",
scale_factor = 0.021842804)
Alignment values:
lowResG_img_no_locs
" giottoImage " with name low_res_no_locs
An object of class
:
Min and max values are Max on x-axis: 10
-axis: 0
Min on x-axis: 10
Max on y-axis: 0
Min on y
:
Boundary adjustment are Max adjustment on x-axis: 0
-axis: 0
Min adjustment on x-axis: 0
Max adjustment on y-axis: 0
Min adjustment on y
:
Boundaries are Image x-axis max boundary: 10
-axis min boundary: 0
Image x-axis max boundary: 10
Image y-axis min boundary: 0
Image y
:
Scale factor x y
0.0218428 0.0218428
:
Resolution x y
45.78167 45.78167
:
File Path [1] "~/Visium_FFPE_Human_Normal_Prostate/spatial/tissue_lowres_image.png"
Note that only default values are given to minmax and boundaries in this case.
(Optional) Providing spatial location information through either of the gobject parameters spat_loc_name or spatial_locs will populate the minmax and boundary slots in an attempt to auto-align the image with the spatial locations. The auto-alignment can be bypassed by using do_manual_adj = TRUE and only the minmax slot will be populated.
With spatial locations, but also with do_manual_adj = TRUE
lowResG_img_manual <- createGiottoImage(gobject = FFPE_prostate,
mg_object = lowResPath,
name = "low_res_manual",
do_manual_adj = TRUE,
xmin_adj = 0,
xmax_adj = 0,
ymin_adj = 0,
ymax_adj = 0,
scale_factor = 0.021842804)
Alignment values:
lowResG_img_manual
" giottoImage " with name low_res_manual
An object of class
:
Min and max values are Max on x-axis: 23520
-axis: 5066
Min on x-axis: -3682
Max on y-axis: -23148
Min on y
:
Boundary adjustment are Max adjustment on x-axis: 0
-axis: 0
Min adjustment on x-axis: 0
Max adjustment on y-axis: 0
Min adjustment on y
:
Boundaries are Image x-axis max boundary: 23520
-axis min boundary: 5066
Image x-axis max boundary: -3682
Image y-axis min boundary: -23148
Image y
:
Scale factor x y
0.0218428 0.0218428
:
Resolution x y
45.78167 45.78167
:
File Path [1] "~/Visium_FFPE_Human_Normal_Prostate/spatial/tissue_lowres_image.png"
When do_manual_adj = TRUE, automatic alignment is bypassed in favor of the four manual adjustment values. These values (Boundary adjustment) default to 0.
# Since lowResG_img_no_locs is not associated with the gobject FFPE_prostate, it
# may not be added to the gobject.
FFPE_prostate = addGiottoImage(gobject = FFPE_prostate,
images = list(lowResG_img))
spatPlot2D(gobject = FFPE_prostate,
show_image = TRUE,
image_name = "low_res",
cell_color = "in_tissue",
save_param = list(save_name = "low_res_IT"))
Manually adjusting the plotting of images comes either during createGiottoImage() using do_manual_adj = TRUE and the four adjustment values (xmin_adj, xmax_adj, ymin_adj, ymax_adj) or after giottoImage creation using updateGiottoImage().
This method is performed by eye and may be necessary depending on preference or if despite accounting for scaling, the image coordinates do not match up with the spatial coordinates for some reason.
# createGiottoImage with manually defined adjustment values
lowResG_img_update_manual <- createGiottoImage(gobject = FFPE_prostate,
mg_object = lowResPath,
name = "low_res_update_manual",
do_manual_adj = TRUE,
xmin_adj = 5066,
xmax_adj = 3949,
ymin_adj = 2078,
ymax_adj = 3682,
scale_factor = 0.021842804)
FFPE_prostate <- addGiottoImage(gobject = FFPE_prostate,
images = list(lowResG_img_update_manual))
spatPlot2D(gobject = FFPE_prostate,
show_image = TRUE,
image_name = "low_res_update_manual",
cell_color = "in_tissue",
save_param = list(save_name = "low_res_update_manual_IT"))
# createGiottoImage with manually defined adjustment values
lowResG_img_to_update <- createGiottoImage(gobject = FFPE_prostate,
mg_object = lowResPath,
name = "low_res_to_update",
do_manual_adj = TRUE,
xmin_adj = 0,
xmax_adj = 0,
ymin_adj = 0,
ymax_adj = 0,
scale_factor = 0.021842804)
FFPE_prostate <- addGiottoImage(gobject = FFPE_prostate,
images = list(lowResG_img_to_update))
spatPlot2D(gobject = FFPE_prostate,
show_image = TRUE,
image_name = "low_res_to_update",
cell_color = "in_tissue",
save_param = list(save_name = "low_res_before_update_IT"))
# Use updateGiottoImage() to update the image adjustment values
FFPE_prostate <- updateGiottoImage(gobject = FFPE_prostate,
image_name = "low_res_to_update",
xmin_adj = 5066,
xmax_adj = 3949,
ymin_adj = 2078,
ymax_adj = 3682)
spatPlot2D(gobject = FFPE_prostate,
show_image = TRUE,
image_name = "low_res_to_update",
cell_color = "in_tissue",
save_param = list(save_name = "low_res_after_update_IT"))
4.3.2 (2023-10-31)
R version : x86_64-apple-darwin20 (64-bit)
Platform: macOS Sonoma 14.3.1
Running under
: default
Matrix products: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
BLAS: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
LAPACK
:
locale1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
[
: America/New_York
time zone: internal
tzcode source
:
attached base packages1] stats graphics grDevices utils datasets methods base
[
:
other attached packages1] Giotto_4.0.2 GiottoClass_0.1.3
[
namespace (and not attached):
loaded via a [1] tidyselect_1.2.0 dplyr_1.1.4 farver_2.1.1
4] GiottoVisuals_0.1.4 R.utils_2.12.3 bitops_1.0-7
[7] fastmap_1.1.1 SingleCellExperiment_1.24.0 RCurl_1.98-1.14
[10] digest_0.6.34 lifecycle_1.0.4 terra_1.7-71
[13] magrittr_2.0.3 compiler_4.3.2 rlang_1.1.3
[16] tools_4.3.2 igraph_2.0.1.1 utf8_1.2.4
[19] yaml_2.3.8 data.table_1.15.0 knitr_1.45
[22] S4Arrays_1.2.0 labeling_0.4.3 reticulate_1.35.0
[25] here_1.0.1 DelayedArray_0.28.0 RColorBrewer_1.1-3
[28] abind_1.4-5 withr_3.0.0 BiocGenerics_0.48.1
[31] R.oo_1.26.0 grid_4.3.2 stats4_4.3.2
[34] fansi_1.0.6 colorspace_2.1-0 ggplot2_3.4.4
[37] scales_1.3.0 gtools_3.9.5 SummarizedExperiment_1.32.0
[40] cli_3.6.2 rmarkdown_2.25 crayon_1.5.2
[43] ragg_1.2.7 generics_0.1.3 rstudioapi_0.15.0
[46] rjson_0.2.21 zlibbioc_1.48.0 parallel_4.3.2
[49] XVector_0.42.0 matrixStats_1.2.0 vctrs_0.6.5
[52] Matrix_1.6-5 jsonlite_1.8.8 GiottoData_0.2.7.0
[55] IRanges_2.36.0 S4Vectors_0.40.2 systemfonts_1.0.5
[58] magick_2.8.2 GiottoUtils_0.1.5 glue_1.7.0
[61] codetools_0.2-19 cowplot_1.1.3 gtable_0.3.4
[64] GenomeInfoDb_1.38.6 GenomicRanges_1.54.1 munsell_0.5.0
[67] tibble_3.2.1 pillar_1.9.0 htmltools_0.5.7
[70] GenomeInfoDbData_1.2.11 R6_2.5.1 textshaping_0.3.7
[73] rprojroot_2.0.4 evaluate_0.23 lattice_0.22-5
[76] Biobase_2.62.0 png_0.1-8 R.methodsS3_1.8.2
[79] backports_1.4.1 SpatialExperiment_1.12.0 Rcpp_1.0.12
[82] SparseArray_1.2.3 checkmate_2.3.1 colorRamp2_0.1.0
[85] xfun_0.42 MatrixGenerics_1.14.0 pkgconfig_2.0.3 [