Microenvironment Example

In this example we will construct synthetic images of cells which demonstrate a 'micro-environmental' effect. More specifically, cells placed close to each other in the image will be similar, mimicing the effect that might be produced by a non-uniform distribution of some chemical over a microscopy plate. Such spatial correlation of phenotypes is also seen in tissue. with this in mind, we will construct a tightly packed arrangment of cells.

The cells are 'stained' for 3 markers

Contents

simucell_data

SimuCell requires the user to specify a structure 'simucell_data' to specify how images shall be generated. 'simucell_data' contains the following fields described in more detail below :

subpopulations

%Create Subpopulation Cell Array
% Subpopulations, i.e. different cells types are the central structure of
% SimuCell. You can have as many subpopulations as you like, each one is
% stores as an element in a cell array.
subpop=cell(0);
% Note: the contents of 'subpop' will eventually be assigned to
% 'simucell_data.subpopulations. The use of the temporary variable
% 'subpop' is for ease of reading

%Define Subpopulation 1
% Each subpopulation is an instance of the 'Subpopulation' class defined by
% SimuCell. All cell properties will appear within properties of this
% class.

% Define Subpopulation 1
subpop{1}=Subpopulation();

%Set the Model Placement
% Placement refers to the position of cell in an image.
% Cells in different subpopulations can display different patterns of
% placement (e.g, one type of cells may be clustered or placed randomly)
% Placement for cells in a subpopulation are specified through the
% placement property in subpopulation, which you need to set the the
% appropriate placement model.
% Models for placments are classes of type SimuCell_Placement_Model, and
% are implemented via plugins (usually placed in the 'plugins/placement/'
% directory).
% Here we choose to have cells placed close to existing cells, and so
% choose the 'Nearby_Placement' model.
subpop{1}.placement=Nearby_Placement();
% The placement models follow the typical model specification
% (see SimuCell_Model, Parameter),  and the user settable parameters can
% be found in the plugin file. These parameters follow the standard set
% framework.
% For this model, probability of a pixel being picked is dependent on its
% distance to the nearest existing cell. The functional form of this
% dependence is the probability density function of a poisson distribution
% with mean specified by the 'distance_to_existing' below
set(subpop{1}.placement,'distance_to_existing',15); % (measured in pixels)
% the boundary is the number of pixels around the edge of the image where
% no cells are placed
set(subpop{1}.placement,'boundary',100);
% probability that the cell is part of the cluster, non-clustered cells
% are placed randomly.
set(subpop{1}.placement,'clustering_probability',0.8);

Set the Object Shape

%Set the Object Shape
% Add a cytoplasm object
% As described in the tutorial, users are required to add and name the
% objects on a subpopulation basis. This is done using the add_object
% function.
add_object(subpop{1},'cytoplasm');
% This will create objects of the specified name inside the objects
% property of the subpopulation object. Thus in this case we have
% subpop{1}.objects.cytoplasm.
% Next we need to choose an appropriate model to render the shape of this
% object. The available shape models are inside tye directory
% 'plugins/shape/'. For organizational purposes, these plugins are placed
% in sub-directories (cytoplasm, nucleus and other).
% We choose to use 'Fluid_Shape' which creates
% elliptically shaped cells normally, but if a cell overlaps with an
% existing cell, it morphs its shape like a fluid around the other cell.
% This produces a tissue like effect.
subpop{1}.objects.cytoplasm.model=Fluid_Shape;
%cell radius in pixels
set(subpop{1}.objects.cytoplasm.model,'radius',40);
% Gives a fairly elliptical shape
set(subpop{1}.objects.cytoplasm.model,'eccentricity',0.7);
set(subpop{1}.objects.cytoplasm.model,'randomness',0.3);

% Add a nucleus object
add_object(subpop{1},'nucleus');
% We choose a nucleus model that creates an elliptical shaped nucleus at
% the center of some other object (in our case the cytoplasm)
subpop{1}.objects.nucleus.model=Centered_Nucleus_Model;
set(subpop{1}.objects.nucleus.model,'radius',15);%nuclear radius in pixels
% nuclei are typically elliptical
set(subpop{1}.objects.nucleus.model,'eccentricity',0.7);
% the nucleus is dran at the center of the cytoplasm
set(subpop{1}.objects.nucleus.model,'centered_around',...
  subpop{1}.objects.cytoplasm);
% make the nuclear shape a little noisy
set(subpop{1}.objects.nucleus.model,'randomness',0.2);
% Note:
% 1) In the centered around, we need to point to another object. We refer
% to the object itself (subpop{1}.objects.cytoplasm) NOT its model
% (subpop{1}.objects.cytoplasm.model)
% 2) The responsability for selecting appropriate models is on the script writer. In
% particular the different object models need to be connected in some way
% (otherwise, the cytoplasm and nucleus of the same cell will be in
% completely different locations). Thus you need to be careful to choose
% one independant model (here the Cytoplasm_Model) that anchors the
% position of the cell, while all other models need to be connected to this
% object (either directy or indirectly).

Define Markers

%Setup Markers
% As described in the tutorial, users next add, name  anc choose colors
% for the markers on asubpopulation basis.
% This is done using the add_marker function. (In
% contrast to the GUI you will have to do this for every subpopulation,
% since we assume different subpopulations can be stained with different
% markers)
% Marker 1
% This will be the microenvironment dependant marker
add_marker(subpop{1},'menv', Colors.Red);
% This will create the object subpop{1}.markers.menv
% As described in the tutorial, marker distribution is specified on an
% object by object basis.
% In our case this involves defining subvariables
% subpop{1}.markers.menv.nucleus and subpop{1}.markers.menv.cytoplasm
% which are automatically created by the definition of the marker
% Marker 2
% This marker avoids the menv marker
add_marker(subpop{1},'GFP', Colors.Green);
% Marker 3
% This marker is confined to the nucleus
add_marker(subpop{1},'DAPI', Colors.Blue);

% In contrast to the shape, marker distribution on an object is specified
% in terms of a series of elementary operations. So the standard workflow
% is to define each operation and add it to the queue of operations for the
% specific marker-object pair. The available operations are present as
% plugins in the 'plugins/markers/' directory.

% As described in the tutorial the first operation typically sets the
% overall level of a marker in the object, while the subsequent operations
% redistribute the intensity distribution within the object.

% Note: We do not define the first two markers on the nucleus, this will
% set their level to be zero in the nucleus (but since the nucleus is
% contained inside the cytoplasm --see compositing -- they need not be
% completely dark)

%%%%%% Microenvironment dependant marker
% The level of this marker is determined by its 'microenvironment'. In other
% words cells near each other in the image will have similar levels of ths
% marker. Additionally the level of this marker is higher at the edges of
% the cells and falls towards the nucleus.
op=Microenvironmental_Marker_Level();
% This plugin first generates a semi-random (with some spatial correlations)
% 'micro-environment' intensity over the image. Then, the level of the the
% marker is proportional to the intensity of the micro-environment at the
% location of the cell.
% The length scale over which spatial correlation exists for the
% microenvironment. (2 means variations at the length of image, 6 is high
% frequency variation)
set(op,'length_scale',3);
% Each higher frequency component amplitude is smaller by this scaling
% factor
set(op,'frequency_falloff',0.8);
% The type of variation in micro-environment. Turbulent causes sharper
% transitions
set(op,'noise_type','Turbulent');
% Once the operation is defined, we add it to the queue
subpop{1}.markers.menv.cytoplasm.AddOperation(op);

% Have the intensity fall off with the distance to the edge
op=Distance_To_Edge_Marker_Gradient();
%the intensity fall off functional form
set(op,'falloff_type','Exponential');
%pixels over which intensity falls off by 1/e
set(op,'falloff_radius',10);
%Intensity decreases with distance to the edge
set(op,'increasing_or_decreasing','Decreasing');
subpop{1}.markers.menv.cytoplasm.AddOperation(op);

%Perlin Texture (scale the intensity from the last step by a noisy texture,
%to make it look more realistic)
op=Perlin_Texture();
% Scale the intensity by noise (multiply) or add noise to the existing
% intensity
set(op,'add_or_multiply','Multiply');
%The amplitude of the noise (0 is not noise, and you probably don't want
%to go much beyond 1, since intensities are in the [0-1] range)
set(op,'amplitude',0.2);
% This descibes the length scale over which intensity varies. 2 is
% low wave-length (coarse variation) and 6 is very fine high frequency
% (fine variation)
set(op,'length_scale',5);
% Each higher frequency component amplitude is smaller by this scaling
%factor
set(op,'frequency_falloff',0.8);
% The type of noise. Turbulent causes sharper transitions
set(op,'noise_type','Turbulent');
subpop{1}.markers.menv.cytoplasm.AddOperation(op);



%%%%%% GFP
% The level of this marker in a cell is inversely correlated with the
% presence of the Red 'menv' marker. This is achieved using the
% 'Constant_Dependant_Marker_Level' plugin.
% It sets the marker level in to a constant, with the value of this
% constant being varying with the mean level of another marker.
op=Constant_Dependant_Marker_Level();
% If x_(m,r) is the mean level in of marker m in region r, then
% this plugin sets the intensity of chosen marker in chosen region to be:
% slope*x_(m,r) + intercept
% slope in the equation above, negative sign means inverse relation
set(op,'slope',-2.5);
%Intercept in equation above. This is the level the marker will have if
%the other marker x_(m,r) is zero
set(op,'intercept',0.9);
% The other marker i.e. m on which this marker depends
set(op,'marker',subpop{1}.markers.menv.cytoplasm);
% The region on which m is calculated i.e. r
set(op,'region',subpop{1}.objects.cytoplasm);
set(op,'func','Mean');
% The last three lines specify that the mean level of the menv marker
% measured on the cytoplasmic region will be used to determine the level of
% GFP.
subpop{1}.markers.GFP.cytoplasm.AddOperation(op);
% Throw in some noise
%Perlin Texture
op=Perlin_Texture();
set(op,'add_or_multiply','Multiply');
set(op,'amplitude',0.1);
set(op,'length_scale',5);
set(op,'frequency_falloff',0.7);
set(op,'noise_type','Turbulent');
subpop{1}.markers.GFP.cytoplasm.AddOperation(op);


%%%%%% DAPI
% DAPI is only present in the nucleus. It shows a slight variation from
% cell to cell and some non-uniform texture
op=Constant_Marker_Level();
% Set a constant marker level (uniform across entire object,
% but varying from cell to cell)
% The marker level for a cell is sampled from a normal distribution with
%this mean
set(op,'mean_level',0.5);
% and this standard deviation
set(op,'sd_level',0.2);
subpop{1}.markers.DAPI.nucleus.AddOperation(op);
%Throw in some noisy texture
op=Perlin_Texture();
set(op,'add_or_multiply','Multiply');
set(op,'amplitude',0.3);
set(op,'length_scale',4);
set(op,'frequency_falloff',0.7);
set(op,'noise_type','Standard 1/f');
subpop{1}.markers.DAPI.nucleus.AddOperation(op);

Set the Composite Type

subpop{1}.compositing=Default_Compositing();
% Compositing governs the rendering of markers when multiple objects, with
% some expression of the same marker, overlap. For example, suppose a
% marker is present in the nucleus and the cytoplasm. The nucleus is
% contained in the cytoplasm, thus the marker level in the nucleus is a
% composite of its expression from the the nucleus and the cytoplasm.
% Presently we support just one compositing model, called default
% compositing. This model determines, at run-time, which objects contain
% which others (cytoplasm contains nucleus). The user can then specify
% the weight given to the container (the contained object gets
% 1-container_weight).
set(subpop{1}.compositing,'container_weight',0);
% In this example the cytoplasm will get 0 weight and nucleus full weight
% nuclear region. Note in the cytoplasmic region where there is no overlap,
% only the model of the marker in the cytoplasm comes into play, and no
% compositing is required.

Set the Cell Artifacts

Add rendering artifacts at a cell by cell level Cell artifacts are added using the add_cell_artifact function. Like markers, they are defined by a series of operations. Thee operations are plugins places in the 'plugins/cell_artifacts/' directory.

%Set the Cell Artifacts
% Makes a specified fracton of cells blurred,
% to mimic an out of focal plane effect
%op=Out_Of_Focus_Cells();
%set(op,'fraction_blurred',0.1); % 10% cells blurred
% blur radius in pixels. 1 is pretty small, 4 produces a clear out of focus
%effect
%set(op,'blur_radius',4);
%subpop{1}.add_cell_artifact(op);

Set Overlap

We can also specify if cells are allowed to overlap, and to what extent. This spans subpopulations, and is stored in the overlap parameter of the simucell_data structure. This is done by specifying a series of rules for maximum allowed overlap: Each rule consists of two parts 1) A list (stored as a cell) of objects on which the overlap is measured 2) The maximum allowed overlap between these objects, measured as a fraction of their areas

overlap=Overlap_Specification;
overlap.AddOverlap({subpop{1}.objects.cytoplasm},0);
simucell_data.overlap=overlap;
% Here we specified that overlap be measured on the cytoplasms of the
% cells, and the 0 means that no overlap is allowed.

% Note:
% 1) Overlaps across subpopulations can be specified. See the polarized
% cell example for a demonstration
% 2) Multiple rules can be added in this way
%   To additionally prevent any nuclear overlap one might add
%   overlap.AddOverlap({subpop{1}.objects.nucleus},0);

Set Image Artifact

simucell_data.image_artifacts=cell(0);
simucell_data.image_artifacts=cell(0);
op=Add_Basal_Brightness();
set(op,'basal_level',0.2);
simucell_data.image_artifacts{1}=op;
op=Radial_Image_Gradient();
set(op,'falloff_type','Gaussian');
set(op,'falloff_radius',500);
set(op,'max_multiplier',1.5);
set(op,'min_multiplier',0.5);
simucell_data.image_artifacts{2}=op;

Set Image Parameters

%Set Number of cell per image
simucell_data.number_of_cells=100;
% Note: If SimuCell cannot fit in any more cells (and still meet the
% overlap conditions) it will generate an image with the maximum number of
% cells it fits in

%Set Image Size (in pixels)
simucell_data.simucell_image_size=[1000,1000];

% You can specify the fractions of cells in the image from the different
% subpopulations (however in this case there is only one subpopulation)
simucell_data.population_fractions=[1];

% assign the subpopulations to the data structure
simucell_data.subpopulations=subpop;

% To invoke the engine
%simucell_result=simucell_engine(simucell_data);
%image(a);
%axis off;
%axis equal;