count_touching_cells uses morphological analysis of nuclear and membrane segmentation maps to find touching cells of paired phenotypes. It reports the number of touching cells found and, optionally, writes image files showing the touching cells.

count_touching_cells(cell_seg_path, pairs, colors = NULL,
  phenotype_rules = NULL, categories = NULL,
  write_images = !is.null(colors), output_base = NULL)



The path to the cell seg data file. The same directory must also contain _memb_seg_map.tif or _binary_seg_maps.tif and, if write_images is true, a TIFF or JPEG composite image from inForm.


A list of pairs of phenotypes. Each entry is a two-element vector. The result will contain one line for each pair showing the number of cells and number of touches.


A named list of phenotype colors to use when drawing the output. Only used when write_images is TRUE.


(Optional) A named list. Item names are phenotype names and must match entries in pairs. Item values are selectors for select_rows.


If given, a vector or list of tissue category names. Categories not in the list will be excluded from the analysis.


If TRUE, for each pair, write an image showing the touching pairs. Requires colors and a composite image in the same directory as the cell seg table.


Base path for image output. If NULL, output will be to the same directory as the cell table.


Returns a data_frame with one row for each pair in pairs, containing these columns:


Slide ID from the data file.


Base file name of the source file with _cell_seg_data.txt stripped off for brevity.


The name of the first phenotype in the touching pair.


The name of the second phenotype in the touching pair.


The total number of phenotype1 cells in the image.


The total number of phenotype2 cells in the image.


The number of phenotype1 cells touching a phenotype2 cell.


The number of phenotype2 cells touching a phenotype1 cell.


The number of mutually touching pairs.


Cells are considered to touch if they have any amount of common membrane as determined by the inForm membrane segmentation. Cells with meet only at a corner, like black squares on a checkerboard, are not counted as touching.

The number of touching cells is reported in three ways. For a pair of phenotypes A and B, this function reports the number of A touching a B, the number of B touching an A, and the number of mutually touching pairs. Note that the number of mutual touches is often larger than the count of either "A touching B" or "B touching A" because a single touching cell may be part of multiple pairs.

The image files written show cells of the selected phenotypes on a background of the composite. Touching cells are filled in the provided color; cells which are not touching the other phenotype are outlined. Image files are written as TIFF files to preserve the fine detail of cell boundaries.

Images are only written when both phenotypes of the pair are represented.

See the tutorial Selecting cells within a cell segmentation table for more on the use of pairs and phenotype_rules.

See also

Other distance functions: compute_all_nearest_distance, count_within_batch, count_within, distance_matrix, find_nearest_distance, spatial_distribution_report, subset_distance_matrix


# This example creates an image in a subdirectory of the
# current user's directory.
cell_seg_path <- sample_cell_seg_path()

pairs <- list(c("CD68+", "CD8+"))
colors <- c("CD68+"='magenta', "CD8+"='yellow')
output_base <- path.expand('~/touches')

count_touching_cells(cell_seg_path, pairs, colors,

# This example will count and image all files in the `base_path` directory.
base_path <- '/path/to/data'
output_base <- file.path(base_path, 'touches')
files <- list_cell_seg_files(base_path)

# The phenotype pairs to locate. This will find CD8 cells touching
# tumor cells, and, separately, CD8 cells touching CD68 cells.
pairs <- list(c("CD8+", "CK+"),
             c("CD8+", "CD68+"))

# Colors for all the phenotypes mentioned in pairs
colors <- list(
  'CD8+' = 'yellow',
  'CK+' = 'cyan',
  'CD68+' = 'magenta'

# Count and visualize touching cells
touch_counts <- purrr::map_df(files, function(path) {
  cat('Processing', path, '\n')
  count_touching_cells(path, pairs, colors, output_base=output_base)

# Save the result
touches_path <- file.path(output_base, 'TouchCounts.csv')
readr::write_csv(touch_counts, touches_path)

# The phenotype definitions can be more complex. The default is to use
# the names in `pairs`. Using `phenotype_rules`, the definition can be
# anything allowed by select_rows().

# You can also limit the tissue category.

# For example, find all touches between lymphocytes and tumor cells
# within the tumor:
pairs <- list(c('Tumor', 'Lymphocyte'))
colors <- list(Tumor='cyan', Lymphocyte='yellow')
phenotype_rules <- list(
  Lymphocyte=c('CD8+', 'FoxP3+')

touch_counts <- map_df(files, function(path) {
  cat('Processing', path, '\n')
  count_touching_cells(path, pairs, colors, phenotype_rules,

# Then write the results as above.
# }