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
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 :
%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 % 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).
%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);
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.
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);
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);
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 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;