<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<protocol VERSION="4">
<blocks>
<block ID="426668492" blockType="plugins.adufour.blocks.tools.input.Sequence" className="plugins.adufour.blocks.tools.input.Sequence" collapsed="false" definedName="Raw data" height="61" keepsResults="true" width="217" xLocation="31" yLocation="5">
<variables>
<input>
<variable ID="input sequence" name="sequence" runtime="false" value="Active Sequence" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="1330600297" blockType="plugins.adufour.blocks.tools.input.Integer" className="plugins.adufour.blocks.tools.input.Integer" collapsed="false" definedName="Pathogen channel" height="61" keepsResults="true" width="231" xLocation="42" yLocation="98">
<variables>
<input>
<variable ID="integer" name="integer" runtime="false" value="2" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="1064542616" blockType="plugins.adufour.blocks.tools.input.Integer" className="plugins.adufour.blocks.tools.input.Integer" collapsed="false" definedName="Min. cell volume (px)" height="61" keepsResults="true" width="231" xLocation="42" yLocation="164">
<variables>
<input>
<variable ID="integer" name="integer" runtime="false" value="500" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="1684662269" blockType="plugins.adufour.blocks.tools.input.Integer" className="plugins.adufour.blocks.tools.input.Integer" collapsed="false" definedName="Max. cell volume (px)" height="61" keepsResults="true" width="233" xLocation="42" yLocation="230">
<variables>
<input>
<variable ID="integer" name="integer" runtime="false" value="10000" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="274572585" blockType="plugins.adufour.blocks.tools.input.Integer" className="plugins.adufour.blocks.tools.input.Integer" collapsed="false" definedName="Tissue channel" height="61" keepsResults="true" width="196" xLocation="43" yLocation="330">
<variables>
<input>
<variable ID="integer" name="integer" runtime="false" value="0" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="1475713663" blockType="plugins.adufour.blocks.tools.input.Integer" className="plugins.adufour.blocks.tools.input.Integer" collapsed="false" definedName="Gaussian smoothing" height="61" keepsResults="true" width="232" xLocation="43" yLocation="395">
<variables>
<input>
<variable ID="integer" name="integer" runtime="false" value="30" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="878524983" blockType="plugins.adufour.blocks.tools.input.Decimal" className="plugins.adufour.blocks.tools.input.Decimal" collapsed="false" definedName="Intensity threshold (%)" height="61" keepsResults="true" width="243" xLocation="43" yLocation="461">
<variables>
<input>
<variable ID="decimal" name="decimal" runtime="false" value="15.0" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="637977385" blockType="plugins.adufour.blocks.tools.input.File" className="plugins.adufour.blocks.tools.input.File" collapsed="false" definedName="Invasion summary" height="61" keepsResults="true" width="218" xLocation="42" yLocation="530">
<variables>
<input>
<variable ID="file" name="file" runtime="false" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="597291176" blockType="plugins.adufour.blocks.tools.input.File" className="plugins.adufour.blocks.tools.input.File" collapsed="false" definedName="Detailed invasion analysis" height="61" keepsResults="true" width="267" xLocation="41" yLocation="594">
<variables>
<input>
<variable ID="file" name="file" runtime="false" visible="true"/>
</input>
<output/>
</variables>
</block>
<block ID="1181124946" blockType="plugins.tprovoost.sequenceblocks.extract.ExtractChannel" className="plugins.tprovoost.sequenceblocks.SequenceBlocks" collapsed="true" definedName="Select tissue channel" height="105" keepsResults="true" width="233" xLocation="302" yLocation="355">
<variables>
<input>
<variable ID="sequence" name="sequence" runtime="false" visible="true"/>
<variable ID="channel" name="channel" runtime="false" visible="true"/>
</input>
<output>
<variable ID="extracted" name="extracted" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="472094882" blockType="plugins.adufour.filtering.GaussianFilter" className="plugins.adufour.filtering.FilterToolbox" collapsed="true" definedName="Gaussian filter" height="149" keepsResults="true" width="232" xLocation="320" yLocation="420">
<variables>
<input>
<variable ID="input" name="input" runtime="false" visible="true"/>
<variable ID="filterX" name="sigma (x)" runtime="false" visible="true"/>
<variable ID="filterY" name="sigma (y)" runtime="false" visible="true"/>
<variable ID="filterZ" name="sigma (z)" runtime="false" value="0.0" visible="true"/>
</input>
<output>
<variable ID="output" name="output" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="948752124" blockType="plugins.adufour.thresholder.Thresholder" className="plugins.adufour.thresholder.Thresholder" collapsed="true" definedName="Thresholder" height="171" keepsResults="true" width="238" xLocation="328" yLocation="486">
<variables>
<input>
<variable ID="Input" name="Input" runtime="false" visible="true"/>
<variable ID="channel" name="channel" runtime="false" value="0" visible="true"/>
<variable ID="Manual thresholds" name="Manual thresholds" runtime="false" visible="true"/>
<variable ID="Treat as percentiles" name="Treat as percentiles" runtime="false" value="true" visible="true"/>
</input>
<output>
<variable ID="output" name="Binary output" runtime="false" visible="true"/>
<variable ID="ROI" name="ROI" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="1005693014" blockType="plugins.adufour.roi.LabelExtractor" className="plugins.adufour.roi.LabelExtractor" collapsed="true" definedName="Extract tissue layers" height="127" keepsResults="false" width="295" xLocation="619" yLocation="486">
<variables>
<input>
<variable ID="input sequence" name="Labeled sequence" runtime="false" visible="true"/>
<variable ID="extract mode" name="Extract" runtime="false" value="ANY_LABEL_VS_BACKGROUND" visible="true"/>
<variable ID="value" name="Value" runtime="false" value="0.0" visible="true"/>
</input>
<output>
<variable ID="ROI" name="Extracted ROI" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="1739071229" blockType="plugins.tprovoost.sequenceblocks.extract.ExtractChannel" className="plugins.tprovoost.sequenceblocks.SequenceBlocks" collapsed="true" definedName="Select pathogen channel" height="105" keepsResults="true" width="254" xLocation="302" yLocation="123">
<variables>
<input>
<variable ID="sequence" name="sequence" runtime="false" visible="true"/>
<variable ID="channel" name="channel" runtime="false" visible="true"/>
</input>
<output>
<variable ID="extracted" name="extracted" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="1218821132" blockType="plugins.adufour.hierarchicalkmeans.HierarchicalKMeans" className="plugins.adufour.hierarchicalkmeans.HierarchicalKMeans" collapsed="false" definedName="Extract pathogens" height="237" keepsResults="true" width="234" xLocation="614" yLocation="98">
<variables>
<input>
<variable ID="Input" name="Input" runtime="false" visible="true"/>
<variable ID="Gaussian pre-filter" name="Gaussian pre-filter" runtime="false" value="3.0" visible="true"/>
<variable ID="Min size (px)" name="Min size (px)" runtime="false" visible="true"/>
<variable ID="Max size (px)" name="Max size (px)" runtime="false" visible="true"/>
<variable ID="Number of classes" name="Number of classes" runtime="false" value="4" visible="true"/>
<variable ID="Final threshold" name="Final threshold" runtime="false" value="0.0" visible="true"/>
</input>
<output>
<variable ID="binary sequence" name="binary sequence" runtime="false" visible="true"/>
<variable ID="output objects" name="objects" runtime="false" visible="true"/>
<variable ID="output regions" name="list of ROI" runtime="false" visible="true"/>
</output>
</variables>
</block>
<block ID="1437039772" blockType="plugins.tprovoost.scripteditor.scriptblock.Javascript" className="plugins.tprovoost.scripteditor.scriptblock.Javascript" collapsed="false" definedName="Final analysis" height="384" keepsResults="false" width="486" xLocation="878" yLocation="43">
<variables>
<input>
<variable ID="Script" name="Script" runtime="false" value="importClass(Packages.icy.util.StringUtil)&#10;importClass(Packages.java.util.ArrayList)&#10;importClass(Packages.java.util.Collections)&#10;importClass(Packages.icy.roi.ROIUtil)&#10;importClass(Packages.java.io.FileWriter)&#10;importClass(Packages.java.io.File)&#10;&#10;dataset = input2.getName()&#10;cells = input0&#10;layers = input1&#10;&#10;// prepare the summary file&#10;if (input3.exists())&#10;{&#10;&#9;summary = new FileWriter(input3, true)&#10;}&#10;else&#10;{&#10;&#9;// create the file and the header row&#10;&#9;summary = new FileWriter(input3)&#10;&#9;summary.write(&quot;Dataset\tModel thickness (um)\tNb. cells\t&quot;)&#10;&#9;for(l=0;l&lt;layers.length;l++)&#10;&#9;{&#10;&#9;&#9;summary.write(&quot;Layer #&quot; + (l+1) + &quot; (um)\t&quot;)&#10;&#9;&#9;summary.write(&quot;Crossing cells\t&quot;)&#10;&#9;&#9;summary.write(&quot;%\t&quot;)&#10;&#9;}&#10;&#9;summary.write(&quot;\n&quot;)&#10;}&#10;&#10;// prepare the detailed analysis file&#10;if (input4.exists())&#10;{&#10;&#9;detail = new FileWriter(input4, true)&#10;}&#10;else&#10;{&#10;&#9;// create the file and the header row&#10;&#9;detail = new FileWriter(input4)&#10;&#9;detail.write(&quot;Dataset\tCell ID\tCrossing depth (um)\tCrossing depth (%)\n&quot;)&#10;}&#10;&#10;&#10;println(&quot;\nInvasion quantification on: &quot; + dataset)&#10;summary.write(dataset + &quot;\t&quot;)&#10;&#10;// 0) retrieve the Z size in um&#10;umZ = input2.getPixelSizeZ()&#10;&#10;// 1) Measure the parameters of the 3D model&#10;&#10;println(&quot;3D model parameters:&quot;)&#10;&#10;zLayers = new ArrayList(layers.length)&#10;&#10;// fuse ROI that share the same Z slice&#10;for(i=0;i&lt;layers.length-1;i++)&#10;{&#10;&#9;ri = layers[i]&#10;&#9;if (ri==null) continue&#10;&#9;&#10; &#9;for(j=i+1;j&lt;layers.length;j++)&#10;&#9;{&#10;&#9;&#9;rj = layers[j]&#10;&#9;&#9;if (rj == null) continue&#10;&#9;&#9;&#10;&#9;&#9;if (ri.getBounds3D().getMinZ() &gt; rj.getBounds3D().getMaxZ()) continue&#10;&#9;&#9;if (ri.getBounds3D().getMaxZ() &lt; rj.getBounds3D().getMinZ()) continue&#10;&#9;&#9;&#10;&#9;&#9;// r1 and r2 share a same Z =&gt; fuse them&#10;&#9;&#9;ri = ri.getUnion(rj)&#10;&#9;&#9;layers[i] = ri&#10;&#9;&#9;layers[j] = null&#10;&#9;}&#10;}&#10;&#10;// retrieve the depth of the cell layers&#10;for(i=0;i&lt;layers.length;i++)&#10;{&#10;&#9;roi = layers[i]&#10;&#9;if (roi == null) continue&#10;&#9;b3 = roi.getBounds3D()&#10;&#9;z = b3.getZ() + b3.getSizeZ() / 2&#10;&#9;zLayers.add(z * umZ)&#10;}&#10;&#10;// sort the layers by ascending depth&#10;Collections.sort(zLayers)&#10;&#10;for(i=0;i&lt;zLayers.size();i++)&#10;{&#10;&#9;println(&quot;  There is a cell layer at Z=&quot; + zLayers.get(i) + &quot; um&quot;)&#10;}&#10;&#10;firstLayer = 0&#10;lastLayer = zLayers.size() - 1&#10;thickness = zLayers.get(lastLayer) - zLayers.get(firstLayer)&#10;println(&quot;  Total thickness: &quot; + thickness + &quot; um&quot;)&#10;summary.write(thickness + &quot;\t&quot;)&#10;&#10;// 2) Measure the invasion&#10;&#10;println(&quot;Invasion parameters:&quot;)&#10;&#10;// count the cells on each side of the layers in order&#10;// [not invading, crossed layer 1, ..., crossed layer N]&#10;invaders = []&#10;for(l=0;l&lt;=zLayers.size();l++)&#10;{&#10;&#9;invaders[l] = 0&#10;}&#10;&#10;println(&quot;  There are &quot; + cells.length + &quot; cells in the field of view&quot;)&#10;summary.write(cells.length + &quot;\t&quot;)&#10;&#10;for(i=0;i&lt;cells.length;i++)&#10;{&#10;&#9;cell = cells[i]&#10;&#9;b3 = cell.getBounds3D()&#10;&#9;zCell = b3.getZ() + b3.getSizeZ() / 2&#10;&#9;zCell *= umZ&#10;&#10;&#9;firstCross = Math.max(0, zCell - zLayers.get(0))&#10;&#9;firstCrossPct = 100.0 * firstCross / thickness&#9;&#9;&#10;&#9;detail.write(dataset + &quot;\t&quot; + (i+1) + &quot;\t&quot; + firstCross + &quot;\t&quot; + firstCrossPct + &quot;\n&quot;)&#10;&#10;&#9;// check which layer is crossed by the current cell&#10;&#9;cellHasCrossed = false&#10;&#9;for(l=zLayers.size();l&gt;0;l--)&#10;&#9;{&#10;&#9;&#9;zLayer = zLayers.get(l-1)&#10;&#9;&#9;cross = zCell - zLayer&#10;&#9;&#9;&#10;&#9;&#9;if (cross &gt; 0)&#10;&#9;&#9;{&#10;&#9;&#9;&#9;cellHasCrossed = true&#10;&#9;&#9;&#9;invaders[l]++&#10;&#9;&#9;&#9;break&#10;&#9;&#9;}&#10;&#9;}&#10;&#9;if(!cellHasCrossed) invaders[0]++&#10;}&#10;&#10;// output&#10;for(l=0;l&lt;invaders.length;l++)&#10;{&#10;&#9;nbCells = invaders[l]&#10;&#9;pct = (100.0 * nbCells / cells.length)&#10;&#9;&#10;&#9;if (l==0)&#10;&#9;{&#10;&#9;&#9;print(&quot;  Cells not invading: &quot;)&#10;&#9;}&#10;&#9;else&#10;&#9;{&#10;&#9;&#9;print(&quot;  Cells crossing layer &quot; + l + &quot;: &quot;)&#10;&#9;&#9;summary.write(zLayers.get(l-1) + &quot;\t&quot; + nbCells + &quot;\t&quot; + pct + &quot;\t&quot;)&#10;&#9;}&#10;&#9;println(nbCells + &quot; (&quot; + StringUtil.toString(pct, 1) + &quot;%)&quot;)&#10;}&#10;&#10;summary.write(&quot;\n&quot;)&#10;summary.flush()&#10;detail.flush()&#10;summary.close()&#10;detail.close()" visible="true"/>
<variable ID="Add Input" name="Add Input" runtime="false" value="4" visible="true"/>
<variable ID="Add output" name="Add output" runtime="false" value="0" visible="true"/>
<variable ID="input0" name="input0" runtime="false" type="[Licy.roi.ROI;" visible="true"/>
<variable ID="464775523" name="input1" runtime="true" type="[Licy.roi.ROI;" visible="true"/>
<variable ID="2051565420" name="input2" runtime="true" type="icy.sequence.Sequence" visible="true"/>
<variable ID="1923555385" name="input3" runtime="true" type="java.io.File" visible="true"/>
<variable ID="1116077287" name="input4" runtime="true" type="java.io.File" visible="true"/>
</input>
<output>
<variable ID="output0" name="output0" runtime="false" type="java.lang.Object" visible="true"/>
</output>
</variables>
</block>
</blocks>
<links>
<link dstBlockID="1181124946" dstVarID="sequence" srcBlockID="426668492" srcVarID="input sequence"/>
<link dstBlockID="1739071229" dstVarID="sequence" srcBlockID="426668492" srcVarID="input sequence"/>
<link dstBlockID="1218821132" dstVarID="Min size (px)" srcBlockID="1064542616" srcVarID="integer"/>
<link dstBlockID="1218821132" dstVarID="Max size (px)" srcBlockID="1684662269" srcVarID="integer"/>
<link dstBlockID="1218821132" dstVarID="Input" srcBlockID="1739071229" srcVarID="extracted"/>
<link dstBlockID="472094882" dstVarID="input" srcBlockID="1181124946" srcVarID="extracted"/>
<link dstBlockID="948752124" dstVarID="Input" srcBlockID="472094882" srcVarID="output"/>
<link dstBlockID="1005693014" dstVarID="input sequence" srcBlockID="948752124" srcVarID="output"/>
<link dstBlockID="1437039772" dstVarID="input0" srcBlockID="1218821132" srcVarID="output regions"/>
<link dstBlockID="1437039772" dstVarID="464775523" srcBlockID="1005693014" srcVarID="ROI"/>
<link dstBlockID="1739071229" dstVarID="channel" srcBlockID="1330600297" srcVarID="integer"/>
<link dstBlockID="1181124946" dstVarID="channel" srcBlockID="274572585" srcVarID="integer"/>
<link dstBlockID="1437039772" dstVarID="2051565420" srcBlockID="426668492" srcVarID="input sequence"/>
<link dstBlockID="472094882" dstVarID="filterX" srcBlockID="1475713663" srcVarID="integer"/>
<link dstBlockID="472094882" dstVarID="filterY" srcBlockID="1475713663" srcVarID="integer"/>
<link dstBlockID="948752124" dstVarID="Manual thresholds" srcBlockID="878524983" srcVarID="decimal"/>
<link dstBlockID="1437039772" dstVarID="1923555385" srcBlockID="637977385" srcVarID="file"/>
<link dstBlockID="1437039772" dstVarID="1116077287" srcBlockID="597291176" srcVarID="file"/>
</links>
</protocol>
