From 831e2f27d207c25a49cf582a39d65296253985ff Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Tue, 10 May 2011 11:03:35 +0000
Subject: [PATCH] LMS-2190 gene and assay view polishing, small names
 refactoring

SVN: 21192
---
 .../FeatureVectorSummaryViewer.java           |  45 +++---
 .../detailviewers/LayoutUtils.java            |   2 +
 .../MaterialReplicaFeatureSummaryViewer.java  | 134 +++++++++-------
 .../detailviewers/PropertiesUtil.java         | 148 ++++++++++++++++++
 .../specific/ScreeningLinkExtractor.java      |   2 +-
 ...MaterialReplicaFeatureSummaryProvider.java |   9 +-
 .../MaterialFeatureVectorSummaryLoader.java   |  82 +++++++---
 .../logic/ReplicateSequenceProvider.java      |  33 ++--
 .../server/logic/WellContentLoader.java       |   5 +-
 .../MaterialAllReplicasFeatureVectors.java    |  16 +-
 .../dto/MaterialReplicaFeatureSummary.java    |   5 +-
 ...aterialFeatureVectorSummaryLoaderTest.java |   2 +-
 12 files changed, 345 insertions(+), 138 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PropertiesUtil.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/FeatureVectorSummaryViewer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/FeatureVectorSummaryViewer.java
index 270396fe9a2..11c2b5c103b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/FeatureVectorSummaryViewer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/FeatureVectorSummaryViewer.java
@@ -18,10 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.
 
 import java.util.Set;
 
-import com.extjs.gxt.ui.client.Style.Orientation;
-import com.extjs.gxt.ui.client.util.Margins;
 import com.extjs.gxt.ui.client.widget.Component;
-import com.extjs.gxt.ui.client.widget.Html;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
 import com.extjs.gxt.ui.client.widget.layout.RowData;
 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
@@ -49,6 +46,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.u
  * 
  * @author Kaloyan Enimanev
  */
+// TODO 2011-05-05, Tomasz Pylak: rename to ExperimentAnalysisSummaryViewer
 public class FeatureVectorSummaryViewer
 {
 
@@ -115,14 +113,14 @@ public class FeatureVectorSummaryViewer
                 @Override
                 public String tryGetLink()
                 {
-                    return ScreeningLinkExtractor.createFeatureVectorSummaryBrowserLink(experiment
-                            .getPermId());
+                    return ScreeningLinkExtractor
+                            .createExperimentAnalysisSummaryBrowserLink(experiment.getPermId());
                 }
 
                 @Override
                 public String getTabTitle()
                 {
-                    return "Feature Vector Summary: " + experiment.getCode();
+                    return "Analysis Summary " + experiment.getCode();
                 }
 
                 @Override
@@ -139,14 +137,13 @@ public class FeatureVectorSummaryViewer
     {
 
         final LayoutContainer panel = new LayoutContainer();
-        panel.setLayout(new RowLayout(Orientation.VERTICAL));
+        panel.setLayout(new RowLayout());
 
-        Widget northPanel = createNorth(viewContext, experiment);
-        panel.add(northPanel);
+        addHeader(panel, viewContext, experiment);
 
         final IDisposableComponent gridComponent =
                 FeatureVectorSummaryGrid.create(viewContext, experiment);
-        panel.add(gridComponent.getComponent());
+        panel.add(gridComponent.getComponent(), new RowData(-1, 1));
 
         return new IDisposableComponent()
             {
@@ -172,24 +169,26 @@ public class FeatureVectorSummaryViewer
             };
     }
 
-    private static Widget createNorth(IViewContext<IScreeningClientServiceAsync> viewContext,
-            Experiment experiment)
+    private static void addHeader(LayoutContainer parentPanel,
+            IViewContext<IScreeningClientServiceAsync> viewContext, Experiment experiment)
     {
+        String headingText = "Assay " + experiment.getCode();
+
         LayoutContainer panel = new LayoutContainer();
-        panel.setLayout(new RowLayout(Orientation.VERTICAL));
+        panel.setLayout(new RowLayout());
 
-        // NOTE: this should be refactored to an external CSS style
-        String headingText = "Assay " + experiment.getCode();
-        Html headingWidget = new Html(headingText);
-        headingWidget.setTagName("h1");
-        panel.add(headingWidget, new RowData(1, -1, headingTitleMargin()));
+        Widget headingWidget = PropertiesUtil.createHeaderTitle(headingText);
+        panel.add(headingWidget, PropertiesUtil.createHeaderTitleLayoutData());
 
-        return panel;
-    }
+        LayoutContainer propertiesPanel = new LayoutContainer();
+        propertiesPanel.setLayout(new RowLayout());
+        int propsHeight = PropertiesUtil.addProperties(experiment, propertiesPanel, null);
+        panel.add(propertiesPanel, new RowData(1, -1));
 
-    private static Margins headingTitleMargin()
-    {
-        return new Margins(0, 0, 20, 0);
+        int headersHeight = 15;
+        int totalHeight = propsHeight + headersHeight;
+        parentPanel.add(panel,
+                new RowData(-1, totalHeight, PropertiesUtil.createHeaderInfoMargin()));
     }
 
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/LayoutUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/LayoutUtils.java
index ba9e29158a7..25795762b8a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/LayoutUtils.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/LayoutUtils.java
@@ -26,6 +26,8 @@ import com.extjs.gxt.ui.client.widget.layout.RowData;
  */
 public class LayoutUtils
 {
+    public static final int ONE_HEADER_LINE_HEIGHT_PX = 15;
+
     private static final int MARGIN_SIZE_PX = 10;
 
     /** @return layout data with big margin on all sides */
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialReplicaFeatureSummaryViewer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialReplicaFeatureSummaryViewer.java
index 5de170c288c..d22f5aab939 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialReplicaFeatureSummaryViewer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialReplicaFeatureSummaryViewer.java
@@ -26,13 +26,12 @@ import java.util.Set;
 
 import com.extjs.gxt.ui.client.Style.Orientation;
 import com.extjs.gxt.ui.client.Style.Scroll;
-import com.extjs.gxt.ui.client.util.Margins;
 import com.extjs.gxt.ui.client.widget.Component;
-import com.extjs.gxt.ui.client.widget.HorizontalPanel;
 import com.extjs.gxt.ui.client.widget.Html;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
 import com.extjs.gxt.ui.client.widget.Text;
 import com.extjs.gxt.ui.client.widget.Viewport;
+import com.extjs.gxt.ui.client.widget.layout.ColumnLayout;
 import com.extjs.gxt.ui.client.widget.layout.RowData;
 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
 import com.extjs.gxt.ui.client.widget.layout.TableLayout;
@@ -54,7 +53,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
@@ -75,6 +73,14 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReplicaIma
  */
 public class MaterialReplicaFeatureSummaryViewer
 {
+    private static final String LOADING_IMAGES_DICT_MSG = "Loading images...";
+
+    private static final String REPLICATE_ABBREV_DICT_MSG = "repl.";
+
+    private static final String NO_IMAGES_AVAILABLE_DICT_MSG = "No images available.";
+
+    private static final String MATERIAL_ID_DICT_MSG = "Id";
+
     private static final int ONE_IMAGE_SIZE_PX = 80;
 
     public static void openTab(IViewContext<IScreeningClientServiceAsync> screeningViewContext,
@@ -88,7 +94,7 @@ public class MaterialReplicaFeatureSummaryViewer
 
     private final IViewContext<IScreeningClientServiceAsync> screeningViewContext;
 
-    public MaterialReplicaFeatureSummaryViewer(
+    private MaterialReplicaFeatureSummaryViewer(
             IViewContext<IScreeningClientServiceAsync> screeningViewContext)
     {
         this.screeningViewContext = screeningViewContext;
@@ -118,7 +124,6 @@ public class MaterialReplicaFeatureSummaryViewer
             screeningViewContext.getCommonService().getExperimentInfo(new TechId(experiment),
                     new AbstractAsyncCallback<Experiment>(screeningViewContext)
                         {
-
                             @Override
                             protected void process(Experiment result)
                             {
@@ -147,7 +152,6 @@ public class MaterialReplicaFeatureSummaryViewer
             screeningViewContext.getService().getMaterialInfo(new TechId(material),
                     new AbstractAsyncCallback<Material>(screeningViewContext)
                         {
-
                             @Override
                             protected void process(Material result)
                             {
@@ -204,19 +208,20 @@ public class MaterialReplicaFeatureSummaryViewer
 
     private class ImagesFoundCallback extends AbstractAsyncCallback<List<WellReplicaImage>>
     {
-        private final LayoutContainer panel;
+        private final LayoutContainer imagesPanel;
 
-        ImagesFoundCallback(LayoutContainer panel)
+        ImagesFoundCallback(LayoutContainer imagesPanel)
         {
             super(screeningViewContext);
-            this.panel = panel;
+            this.imagesPanel = imagesPanel;
         }
 
         @Override
         protected void process(List<WellReplicaImage> images)
         {
-            panel.add(createImagePanel(images));
-            panel.layout();
+            imagesPanel.removeAll();
+            imagesPanel.add(createImagePanel(images));
+            imagesPanel.layout();
         }
     }
 
@@ -224,7 +229,7 @@ public class MaterialReplicaFeatureSummaryViewer
     {
         if (images.isEmpty())
         {
-            return new Text("No images available.");
+            return new Text(NO_IMAGES_AVAILABLE_DICT_MSG);
         }
         String displayTypeId = ScreeningDisplayTypeIDGenerator.EXPERIMENT_CHANNEL.createID(null);
         final IDefaultChannelState defaultChannelState =
@@ -245,15 +250,20 @@ public class MaterialReplicaFeatureSummaryViewer
             labelToReplicasMap.remove(orphanGroupKey);
         }
         panel.add(createBiologicalReplicatesImagesPanel(labelToReplicasMap, channelChooser));
+        ensureAllImagesVisible(panel);
+        return panel;
+    }
+
+    // WORKAROUND: in normal mode the height of menu and tab is not taken into account,
+    // so we add empty space to make
+    private void ensureAllImagesVisible(LayoutContainer panel)
+    {
         if (screeningViewContext.isSimpleOrEmbeddedMode() == false)
         {
-            // WORKAROUND: in normal mode the height of menu and tab is not taken into account,
-            // so we add empty space to make
             Text box = new Text();
             box.setHeight(100);
             panel.add(box);
         }
-        return panel;
     }
 
     private Widget createOrphanTechnicalReplicatesPanel(
@@ -333,7 +343,7 @@ public class MaterialReplicaFeatureSummaryViewer
 
     private Widget createTechnicalReplicateLabel(int technicalReplicateSequence)
     {
-        return new Text("repl. " + technicalReplicateSequence);
+        return new Text(REPLICATE_ABBREV_DICT_MSG + " " + technicalReplicateSequence);
     }
 
     private Widget createEmptyBox()
@@ -413,8 +423,8 @@ public class MaterialReplicaFeatureSummaryViewer
         panel.setLayout(new RowLayout(Orientation.VERTICAL));
         panel.setScrollMode(Scroll.AUTOY);
 
-        final Widget northPanel = createNorth(screeningViewContext, experiment, material);
-        panel.add(northPanel);
+        Widget materialInfo = createMaterialInfo(screeningViewContext, experiment, material);
+        panel.add(materialInfo, new RowData(-1, -1, PropertiesUtil.createHeaderInfoMargin()));
 
         final IDisposableComponent gridComponent =
                 MaterialReplicaFeatureSummaryGrid.create(screeningViewContext, new TechId(
@@ -422,8 +432,11 @@ public class MaterialReplicaFeatureSummaryViewer
         // NOTE: if the width is 100% then the vertical scrollbar of the grid is not visible
         panel.add(gridComponent.getComponent(), new RowData(0.97, 400));
 
+        LayoutContainer imagesPanel = new LayoutContainer();
+        imagesPanel.add(new Text(LOADING_IMAGES_DICT_MSG));
+        panel.add(imagesPanel);
         screeningViewContext.getService().listWellImages(new TechId(material.getId()),
-                new TechId(experiment.getId()), new ImagesFoundCallback(panel));
+                new TechId(experiment.getId()), new ImagesFoundCallback(imagesPanel));
 
         return new IDisposableComponent()
             {
@@ -449,43 +462,45 @@ public class MaterialReplicaFeatureSummaryViewer
             };
     }
 
-    private static Widget createNorth(IViewContext<IScreeningClientServiceAsync> viewContext,
-            Experiment experiment, Material material)
+    private static Widget createMaterialInfo(
+            final IViewContext<IScreeningClientServiceAsync> viewContext,
+            final Experiment experiment, final Material material)
     {
-        HorizontalPanel panel = new HorizontalPanel();
+        LayoutContainer panel = new LayoutContainer();
+        panel.setLayout(new RowLayout());
 
-        Widget left = createNorthLeft(viewContext, experiment, material);
-        panel.add(left);
+        Widget headerWidget = createHeaderWithLinks(viewContext, experiment, material);
+        panel.add(headerWidget, PropertiesUtil.createHeaderTitleLayoutData());
 
-        Widget right = createNorthRight(viewContext, experiment, material);
-        panel.add(right);
+        LayoutContainer materialPropertiesPanel = createMaterialPropertiesPanel(material);
+        panel.add(materialPropertiesPanel);
 
         return panel;
     }
 
-    private static Widget createNorthLeft(
+    private static Widget createHeaderWithLinks(
             final IViewContext<IScreeningClientServiceAsync> viewContext,
             final Experiment experiment, final Material material)
     {
-        LayoutContainer panel = new LayoutContainer();
-        panel.setLayout(new RowLayout(Orientation.VERTICAL));
+        Widget headingWidget = createHeaderTitle(experiment, material);
+        Text emptyBox = new Text();
+        emptyBox.setWidth(200);
+        Widget assayAnalysisSummaryLink =
+                createAssayAnalysisSummaryLink(viewContext, experiment, material);
+        LayoutContainer headerPanel = new LayoutContainer();
+        headerPanel.setLayout(new ColumnLayout());
+        headerPanel.add(headingWidget);
+        headerPanel.add(emptyBox);
+        headerPanel.add(assayAnalysisSummaryLink);
+        return headerPanel;
+    }
 
+    private static Html createHeaderTitle(final Experiment experiment, final Material material)
+    {
         String headingText =
                 getMaterialType(material) + " " + getMaterialName(material) + " in assay "
                         + experiment.getCode();
-
-        Html headingWidget = createHeader(headingText);
-        panel.add(headingWidget, new RowData(1, -1, new Margins(0, 0, 20, 0)));
-
-        return panel;
-    }
-
-    private static Html createHeader(String headingText)
-    {
-        Html headingWidget = new Html(headingText);
-        // NOTE: this should be refactored to an external CSS style
-        headingWidget.setTagName("h1");
-        return headingWidget;
+        return PropertiesUtil.createHeaderTitle(headingText);
     }
 
     private static String getMaterialType(Material material)
@@ -506,29 +521,24 @@ public class MaterialReplicaFeatureSummaryViewer
         if (material.getEntityType().getCode()
                 .equalsIgnoreCase(ScreeningConstants.GENE_PLUGIN_TYPE_CODE))
         {
-            for (IEntityProperty property : material.getProperties())
+            String geneSymbol =
+                    PropertiesUtil.tryFindProperty(material, ScreeningConstants.GENE_SYMBOLS);
+            if (geneSymbol != null)
             {
-                if (property.getPropertyType().getCode()
-                        .equalsIgnoreCase(ScreeningConstants.GENE_SYMBOLS))
-                {
-                    return property.tryGetAsString();
-                }
+                return geneSymbol;
             }
         }
         return material.getCode();
     }
 
-    private static Widget createNorthRight(
+    private static Widget createAssayAnalysisSummaryLink(
             final IViewContext<IScreeningClientServiceAsync> viewContext,
             final Experiment experiment, final Material material)
     {
-        LayoutContainer panel = new LayoutContainer();
-        panel.setLayout(new RowLayout(Orientation.VERTICAL));
-
         // add link to feature vector summary for the experiment
         String linkUrl =
-                ScreeningLinkExtractor
-                        .createFeatureVectorSummaryBrowserLink(experiment.getPermId());
+                ScreeningLinkExtractor.createExperimentAnalysisSummaryBrowserLink(experiment
+                        .getPermId());
         String linkText = "Show assay " + experiment.getCode() + " summary";
         Widget linkWidget = LinkRenderer.getLinkWidget(linkText, new ClickHandler()
             {
@@ -539,11 +549,17 @@ public class MaterialReplicaFeatureSummaryViewer
                     FeatureVectorSummaryViewer.openTab(viewContext, experiment.getPermId());
                 }
             }, linkUrl);
+        return linkWidget;
+    }
 
-        HorizontalPanel linkPanel = new HorizontalPanel();
-        linkPanel.add(linkWidget);
-        panel.add(linkPanel, new RowData(-1, -1, new Margins(0, 0, 20, 200)));
-
-        return panel;
+    private static LayoutContainer createMaterialPropertiesPanel(final Material material)
+    {
+        LayoutContainer propertiesPanel = new LayoutContainer();
+        propertiesPanel.setLayout(new RowLayout());
+        Map<String, String> additionalProperties = new HashMap<String, String>();
+        additionalProperties.put(MATERIAL_ID_DICT_MSG, material.getCode());
+        PropertiesUtil.addProperties(material, propertiesPanel, additionalProperties,
+                ScreeningConstants.GENE_SYMBOLS);
+        return propertiesPanel;
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PropertiesUtil.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PropertiesUtil.java
new file mode 100644
index 00000000000..37e4b9bbae0
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PropertiesUtil.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
+import com.extjs.gxt.ui.client.Style.VerticalAlignment;
+import com.extjs.gxt.ui.client.util.Margins;
+import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.LayoutContainer;
+import com.extjs.gxt.ui.client.widget.Text;
+import com.extjs.gxt.ui.client.widget.layout.RowData;
+import com.extjs.gxt.ui.client.widget.layout.TableData;
+import com.extjs.gxt.ui.client.widget.layout.TableLayout;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.lang.StringEscapeUtils;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolderWithProperties;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
+
+/**
+ * Utility methods to display properties and header in the publication views.
+ * 
+ * @author Tomasz Pylak
+ */
+public class PropertiesUtil
+{
+    public static String tryFindProperty(IEntityPropertiesHolder propertiesHolder,
+            String propertyCode)
+    {
+        for (IEntityProperty property : propertiesHolder.getProperties())
+        {
+            if (property.getPropertyType().getCode().equalsIgnoreCase(propertyCode))
+            {
+                return property.tryGetAsString();
+            }
+        }
+        return null;
+    }
+
+    /** @return estimated height */
+    public static int addProperties(IEntityInformationHolderWithProperties propertiesHolder,
+            LayoutContainer panel,
+            Map<String/* label */, String/* value */> additionalPropertiesOrNull,
+            String... excludedPropertyCodes)
+    {
+        LayoutContainer propertiesPanel = new LayoutContainer();
+        propertiesPanel.setLayout(new TableLayout(3));
+
+        Map<String, String> propertiesMap =
+                createSortedMap(propertiesHolder, excludedPropertyCodes, additionalPropertiesOrNull);
+        int height = 0;
+        for (Entry<String, String> entry : propertiesMap.entrySet())
+        {
+            addProperty(propertiesPanel, entry.getKey(), entry.getValue());
+            height += getEstimatedHeight(entry.getValue());
+        }
+        panel.add(propertiesPanel);
+        return height;
+    }
+
+    private static Map<String, String> createSortedMap(
+            IEntityInformationHolderWithProperties propertiesHolder,
+            String[] excludedPropertyCodes, Map<String, String> additionalPropertiesOrNull)
+    {
+        Set<String> excludedPropertyCodesSet =
+                new HashSet<String>(Arrays.asList(excludedPropertyCodes));
+
+        Map<String, String> propertiesMap = new TreeMap<String, String>();
+        for (IEntityProperty property : propertiesHolder.getProperties())
+        {
+            PropertyType propertyType = property.getPropertyType();
+            if (excludedPropertyCodesSet.contains(propertyType.getCode()) == false)
+            {
+                String value = property.tryGetAsString();
+                if (value != null && value.length() > 0)
+                {
+                    propertiesMap.put(propertyType.getLabel(), value);
+                }
+            }
+        }
+        if (additionalPropertiesOrNull != null)
+        {
+            for (Entry<String, String> entry : additionalPropertiesOrNull.entrySet())
+            {
+                propertiesMap.put(entry.getKey(), entry.getValue());
+            }
+        }
+        return propertiesMap;
+    }
+
+    private static void addProperty(LayoutContainer propertiesPanel, String label, String value)
+    {
+        TableData labelLayout = new TableData(HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
+        labelLayout.setWidth("80px");
+        propertiesPanel.add(new Html(label + ": "), labelLayout);
+        TableData spacerLayout = new TableData();
+        spacerLayout.setWidth("5px");
+        propertiesPanel.add(new Text(""), spacerLayout);
+        TableData valueLayout = new TableData(HorizontalAlignment.LEFT, VerticalAlignment.TOP);
+        propertiesPanel.add(new Html(StringEscapeUtils.unescapeHtml(value)), valueLayout);
+    }
+
+    private static int getEstimatedHeight(String text)
+    {
+        int charsPerLine = 150;
+        return LayoutUtils.ONE_HEADER_LINE_HEIGHT_PX * ((text.length() / charsPerLine) + 1);
+    }
+
+    public static Margins createHeaderInfoMargin()
+    {
+        return new Margins(3, 3, 10, 3);
+    }
+
+    public static RowData createHeaderTitleLayoutData()
+    {
+        return new RowData(-1, -1, new Margins(0, 0, 5, 0));
+    }
+
+    public static Html createHeaderTitle(String headingText)
+    {
+        Html headingWidget = new Html(headingText);
+        // NOTE: this should be refactored to an external CSS style
+        headingWidget.setTagName("h1");
+        return headingWidget;
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
index fad783068ca..264b99992b7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
@@ -88,7 +88,7 @@ public class ScreeningLinkExtractor extends LinkExtractor
         return tryPrint(url);
     }
 
-    public static final String createFeatureVectorSummaryBrowserLink(String experimentPermId)
+    public static final String createExperimentAnalysisSummaryBrowserLink(String experimentPermId)
     {
         URLMethodWithParameters url = new URLMethodWithParameters("");
         url.addParameter(BasicConstant.LOCATOR_ACTION_PARAMETER, FEATURE_VECTOR_SUMMARY_ACTION);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/MaterialReplicaFeatureSummaryProvider.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/MaterialReplicaFeatureSummaryProvider.java
index e8a3324832c..bcd8e51afe5 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/MaterialReplicaFeatureSummaryProvider.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/MaterialReplicaFeatureSummaryProvider.java
@@ -88,7 +88,7 @@ class MaterialReplicaFeatureSummaryProvider extends
             builder.columnGroup(subgroup);
         }
 
-        if (rows.get(0).getTechnicalReplicates() != null)
+        if (rows.get(0).getDirectTechnicalReplicates() != null)
         {
             builder.columnGroup(DEFAULT_SUBGROUP);
         }
@@ -111,7 +111,8 @@ class MaterialReplicaFeatureSummaryProvider extends
         builder.column(DEVIATION).addDouble(row.getFeatureVectorDeviation());
         builder.column(RANK).addInteger((long) row.getFeatureVectorRank());
 
-        MaterialBiologicalReplicateFeatureSummary defaultSubgroup = row.getTechnicalReplicates();
+        MaterialBiologicalReplicateFeatureSummary defaultSubgroup =
+                row.getDirectTechnicalReplicates();
         if (defaultSubgroup != null)
         {
             addSubgroup(builder, DEFAULT_SUBGROUP, "", defaultSubgroup);
@@ -141,7 +142,9 @@ class MaterialReplicaFeatureSummaryProvider extends
                     .withTitle(replicaColumnTitle).addDouble((double) featureValues[i]);
         }
 
-        if (false == DEFAULT_SUBGROUP.equals(groupId))
+        // aggregates should be shown only for biological replicates which have more than one
+        // technical replicate
+        if (false == DEFAULT_SUBGROUP.equals(groupId) && featureValues.length > 1)
         {
             MaterialReplicaSummaryAggregationType aggregationType =
                     subgroup.getSummaryAggregationType();
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
index ccc887bbf1f..672cee58449 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import ch.rinn.restrictions.Private;
@@ -77,8 +78,6 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         {
             return replicaRows;
         }
-        final List<MaterialBiologicalReplicateFeatureVector> backendSubgroups =
-                backendResult.getSubgroups();
 
         float[] featureVectorDeviatons =
                 backendResult.getGeneralSummary().getFeatureVectorDeviations();
@@ -99,18 +98,20 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
             replicaRow.setFeatureVectorRank(featureVectorRanks[i]);
             replicaRow.setFeatureDescription(featureDescriptions.get(i));
 
-            float[] defaultFeatureValues = extractFeatureValues(i, backendResult.getReplicas());
+            float[] defaultFeatureValues =
+                    extractFeatureValues(i, backendResult.getDirectTechnicalReplicates());
             if (defaultFeatureValues != null)
             {
                 MaterialBiologicalReplicateFeatureSummary defaultReplica =
                         new MaterialBiologicalReplicateFeatureSummary(defaultFeatureValues, 0,
                                 MaterialReplicaSummaryAggregationType.MEDIAN);
-                replicaRow.setTechnicalReplicates(defaultReplica);
+                replicaRow.setDirectTechnicalReplicates(defaultReplica);
             }
 
+            final List<MaterialBiologicalReplicateFeatureVector> backendSubgroups =
+                    backendResult.getBiologicalReplicates();
             List<MaterialBiologicalReplicateFeatureSummary> subgroups =
                     new ArrayList<MaterialBiologicalReplicateFeatureSummary>();
-            replicaRow.setBiologicalRelicates(subgroups);
             for (int tmp = 0; tmp < backendSubgroups.size(); tmp++)
             {
                 MaterialBiologicalReplicateFeatureVector backendGroup = backendSubgroups.get(tmp);
@@ -122,6 +123,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
                                 aggregatedSummaries[i], backendGroup.getSummaryAggregationType());
                 subgroups.add(subgroup);
             }
+            replicaRow.setBiologicalRelicates(subgroups);
         }
         return replicaRows;
     }
@@ -135,7 +137,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
             return subgroupLabels;
         }
         for (MaterialBiologicalReplicateFeatureVector backendSubgroup : backendResultOrNull
-                .getSubgroups())
+                .getBiologicalReplicates())
         {
             subgroupLabels.add(backendSubgroup.getSubgroupLabel());
         }
@@ -148,8 +150,8 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         float[] result = new float[replicas.size()];
         for (int pos = 0; pos < result.length; pos++)
         {
-            float[] aggregatedValues = replicas.get(pos).getFeatueVector();
-            result[pos] = aggregatedValues[i];
+            float[] featureVector = replicas.get(pos).getFeatueVector();
+            result[pos] = featureVector[i];
         }
         return result;
     }
@@ -191,15 +193,11 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
                 new ReplicateSequenceProvider(materialWells,
                         settings.getBiologicalReplicatePropertyTypeCodes());
 
-        List<MaterialBiologicalReplicateFeatureVector> subgroups = Collections.emptyList();
-        List<MaterialTechnicalReplicateFeatureVector> replicas = Collections.emptyList();
-        if (replicaSequences.hasNoBiologicalReplicates())
-        {
-            replicas = createTechnicalReplicas(materialWells, replicaSequences);
-        } else
-        {
-            subgroups = createBiologicalReplicates(materialWells, replicaSequences);
-        }
+        List<MaterialBiologicalReplicateFeatureVector> subgroups =
+                createBiologicalReplicates(materialWells, replicaSequences);
+        List<MaterialTechnicalReplicateFeatureVector> replicas =
+                filterDirectTechnicalReplicas(materialWells, replicaSequences);
+
         return new MaterialAllReplicasFeatureVectors(experimentWells.getFeatureDescriptions(),
                 materialGeneralSummary, subgroups, replicas);
     }
@@ -213,7 +211,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         List<MaterialBiologicalReplicateFeatureVector> subgroups =
                 new ArrayList<MaterialBiologicalReplicateFeatureVector>();
         MaterialReplicaSummaryAggregationType aggregationType = settings.getAggregationType();
-        for (Integer biologicalReplicateSeq : replicaSequences.getBiologicalReplicateKeys())
+        for (Integer biologicalReplicateSeq : replicaSequences.getBiologicalReplicateSequences())
         {
             List<IWellData> technicalReplicateWells =
                     biologicalReplicateMap.getOrDie(biologicalReplicateSeq);
@@ -233,7 +231,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
                 WellReplicaSummaryCalculator.calculateSummaryFeatureVector(technicalReplicateWells,
                         aggregationType);
         List<MaterialTechnicalReplicateFeatureVector> replicas =
-                createTechnicalReplicas(technicalReplicateWells, replicaSequences);
+                createTechnicalReplicates(technicalReplicateWells, replicaSequences);
         String subgroupLabel = getSubgroupLabel(technicalReplicateWells, replicaSequences);
         return new MaterialBiologicalReplicateFeatureVector(replicas, aggregatedSummary,
                 aggregationType, subgroupLabel);
@@ -246,7 +244,9 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         // all wells belong to the same subgroup, so it does not matter which one we take
         Sample well = subgroupWellDataList.get(0).getWell();
 
-        return replicaSequences.getBiologicalReplicateLabel(well);
+        String label = replicaSequences.tryGetBiologicalReplicateLabel(well);
+        assert label != null : "no biological replicates!";
+        return label;
     }
 
     private MaterialFeatureVectorSummary tryCalculateMaterialSummary(TechId materialId,
@@ -257,14 +257,30 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         return tryFindMaterialSummary(materialId, featureSummaries);
     }
 
-    private static List<MaterialTechnicalReplicateFeatureVector> createTechnicalReplicas(
-            List<IWellData> materialWellDataList, ReplicateSequenceProvider replicaSequences)
+    // chooses wells which have no information about which biological replicate they are
+    private static List<MaterialTechnicalReplicateFeatureVector> filterDirectTechnicalReplicas(
+            List<IWellData> materialWellDataList, final ReplicateSequenceProvider replicaSequences)
+    {
+        List<IWellData> directTechnicalReplicas =
+                CollectionUtils.filter(materialWellDataList, new ICollectionFilter<IWellData>()
+                    {
+                        public boolean isPresent(IWellData element)
+                        {
+                            return replicaSequences.isBiologicalReplicate(element) == false;
+                        }
+                    });
+        sortByTechnicalReplicateSequence(directTechnicalReplicas, replicaSequences);
+        return createTechnicalReplicates(directTechnicalReplicas, replicaSequences);
+    }
+
+    private static List<MaterialTechnicalReplicateFeatureVector> createTechnicalReplicates(
+            List<IWellData> wells, final ReplicateSequenceProvider replicaSequences)
     {
         List<MaterialTechnicalReplicateFeatureVector> replicas =
                 new ArrayList<MaterialTechnicalReplicateFeatureVector>();
-        for (IWellData wellData : materialWellDataList)
+        for (IWellData wellData : wells)
         {
-            int replicaSequenceNumber = replicaSequences.getTechnicalReplicateSequenceNum(wellData);
+            int replicaSequenceNumber = replicaSequences.getTechnicalReplicateSequence(wellData);
             MaterialTechnicalReplicateFeatureVector featureVector =
                     new MaterialTechnicalReplicateFeatureVector(replicaSequenceNumber,
                             wellData.getFeatureVector());
@@ -273,6 +289,22 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         return replicas;
     }
 
+    private static void sortByTechnicalReplicateSequence(List<IWellData> materialWellDataList,
+            final ReplicateSequenceProvider replicaSequences)
+    {
+        Collections.sort(materialWellDataList, new Comparator<IWellData>()
+            {
+                public int compare(IWellData w1, IWellData w2)
+                {
+                    Integer replicaSequenceNumber1 =
+                            replicaSequences.getTechnicalReplicateSequence(w1);
+                    Integer replicaSequenceNumber2 =
+                            replicaSequences.getTechnicalReplicateSequence(w2);
+                    return replicaSequenceNumber1.compareTo(replicaSequenceNumber2);
+                }
+            });
+    }
+
     private static List<IWellData> filterWellsByMaterial(List<IWellData> wellDataList,
             final TechId materialId)
     {
@@ -295,7 +327,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
             {
                 public Integer getKey(IWellData wellData)
                 {
-                    return replicaSequences.tryGetBiologicalReplicateSequenceNum(wellData.getWell());
+                    return replicaSequences.tryGetBiologicalReplicateSequence(wellData.getWell());
                 }
             });
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ReplicateSequenceProvider.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ReplicateSequenceProvider.java
index ba11ffca355..69d334ba5c0 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ReplicateSequenceProvider.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ReplicateSequenceProvider.java
@@ -22,7 +22,6 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import ch.systemsx.cisd.common.collections.GroupByMap;
 import ch.systemsx.cisd.common.collections.IKeyExtractor;
@@ -46,14 +45,15 @@ class ReplicateSequenceProvider
     public ReplicateSequenceProvider(List<? extends IEntityPropertiesHolder> replicaWells,
             List<String> biologicalReplicatePropertyTypeCodesOrNull)
     {
-        this.biologicalReplicatePropertyTypeCodesOrNull = biologicalReplicatePropertyTypeCodesOrNull;
+        this.biologicalReplicatePropertyTypeCodesOrNull =
+                biologicalReplicatePropertyTypeCodesOrNull;
         this.biologicalReplicateSeqMap = new LinkedHashMap<Double, Integer>();
         this.technicalReplicateSeqMap = new LinkedHashMap<Long, Integer>();
 
         GroupByMap<Double, IEntityPropertiesHolder> biologicalReplicates =
                 groupByBiologicalReplicate(replicaWells);
         int biologicalReplicateSeq = 1;
-        for (Double biologicalReplicateKey : createSortedCopy(biologicalReplicates.getKeys()))
+        for (Double biologicalReplicateKey : biologicalReplicates.getKeys())
         {
             if (biologicalReplicateKey != null)
             {
@@ -70,7 +70,8 @@ class ReplicateSequenceProvider
         }
     }
 
-    public Collection<Integer> getBiologicalReplicateKeys()
+    /** @return sequences of biological replicas, all keys are not null. */
+    public Collection<Integer> getBiologicalReplicateSequences()
     {
         return createSortedCopy(biologicalReplicateSeqMap.values());
     }
@@ -87,8 +88,14 @@ class ReplicateSequenceProvider
             });
     }
 
+    /** @return true if this well has information about which biological replicate it is. */
+    public boolean isBiologicalReplicate(IEntityPropertiesHolder well)
+    {
+        return tryFindSubgroup(well) != null;
+    }
+
     /** Subgroup sequence, the same for all technical replicates of one biological replicate. */
-    public Integer tryGetBiologicalReplicateSequenceNum(IEntityPropertiesHolder well)
+    public Integer tryGetBiologicalReplicateSequence(IEntityPropertiesHolder well)
     {
         Double subgroupKey = tryFindSubgroup(well);
         if (subgroupKey == null)
@@ -103,7 +110,7 @@ class ReplicateSequenceProvider
     /**
      * Technical Replicate Sequence (unique in one biological replicate)
      */
-    public int getTechnicalReplicateSequenceNum(IEntityPropertiesHolder well)
+    public int getTechnicalReplicateSequence(IEntityPropertiesHolder well)
     {
         return technicalReplicateSeqMap.get(well.getId());
     }
@@ -115,15 +122,13 @@ class ReplicateSequenceProvider
         return sortedKeys;
     }
 
-    public boolean hasNoBiologicalReplicates()
+    public String tryGetBiologicalReplicateLabel(IEntityPropertiesHolder well)
     {
-        Set<Double> keys = biologicalReplicateSeqMap.keySet();
-        return keys.size() == 1 && keys.contains(null);
-    }
-
-    public String getBiologicalReplicateLabel(IEntityPropertiesHolder well)
-    {
-        int biologicalReplicateSeq = tryGetBiologicalReplicateSequenceNum(well);
+        Integer biologicalReplicateSeq = tryGetBiologicalReplicateSequence(well);
+        if (biologicalReplicateSeq == null)
+        {
+            return null;
+        }
         IEntityProperty subgroupProperty = tryFindSubgroupProperty(well);
         assert subgroupProperty != null : "cannot fnd the subgroup property";
         boolean isMaterialProperty = (subgroupProperty.getMaterial() != null);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
index 99757e5a419..49a4459d5ff 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
@@ -169,8 +169,9 @@ public class WellContentLoader extends AbstractContentLoader
             ReplicateSequenceProvider replicaSequences)
     {
         int technicalReplicaSequenceNumber =
-                replicaSequences.getTechnicalReplicateSequenceNum(wellContent);
-        String biologicalReplicateLabel = replicaSequences.getBiologicalReplicateLabel(wellContent);
+                replicaSequences.getTechnicalReplicateSequence(wellContent);
+        String biologicalReplicateLabel =
+                replicaSequences.tryGetBiologicalReplicateLabel(wellContent);
         return new WellReplicaImage(wellContent, technicalReplicaSequenceNumber,
                 biologicalReplicateLabel);
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/MaterialAllReplicasFeatureVectors.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/MaterialAllReplicasFeatureVectors.java
index 658782483fb..c509cde17e6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/MaterialAllReplicasFeatureVectors.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/MaterialAllReplicasFeatureVectors.java
@@ -22,10 +22,10 @@ public class MaterialAllReplicasFeatureVectors implements ISerializable
     private MaterialFeatureVectorSummary generalSummary;
 
     // NOTE: Can be empty.
-    private List<MaterialBiologicalReplicateFeatureVector> subgroups;
+    private List<MaterialBiologicalReplicateFeatureVector> biologicalReplicates;
 
     // NOTE: Can be empty. Used for replicas which have no subgroups
-    private List<MaterialTechnicalReplicateFeatureVector> replicas;
+    private List<MaterialTechnicalReplicateFeatureVector> directTechnicalReplicates;
 
     // GWT only
     @SuppressWarnings("unused")
@@ -40,8 +40,8 @@ public class MaterialAllReplicasFeatureVectors implements ISerializable
     {
         this.featureDescriptions = featureDescriptions;
         this.generalSummary = generalSummary;
-        this.subgroups = subgroups;
-        this.replicas = replicas;
+        this.biologicalReplicates = subgroups;
+        this.directTechnicalReplicates = replicas;
     }
 
     public List<CodeAndLabel> getFeatureDescriptions()
@@ -54,14 +54,14 @@ public class MaterialAllReplicasFeatureVectors implements ISerializable
         return generalSummary;
     }
 
-    public List<MaterialBiologicalReplicateFeatureVector> getSubgroups()
+    public List<MaterialBiologicalReplicateFeatureVector> getBiologicalReplicates()
     {
-        return subgroups;
+        return biologicalReplicates;
     }
 
-    public List<MaterialTechnicalReplicateFeatureVector> getReplicas()
+    public List<MaterialTechnicalReplicateFeatureVector> getDirectTechnicalReplicates()
     {
-        return replicas;
+        return directTechnicalReplicates;
     }
 
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialReplicaFeatureSummary.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialReplicaFeatureSummary.java
index eb94e95da5d..a5e5d35e584 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialReplicaFeatureSummary.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialReplicaFeatureSummary.java
@@ -96,12 +96,13 @@ public class MaterialReplicaFeatureSummary implements ISerializable
         this.biologicalRelicates = replicaSubgroups;
     }
 
-    public MaterialBiologicalReplicateFeatureSummary getTechnicalReplicates()
+    public MaterialBiologicalReplicateFeatureSummary getDirectTechnicalReplicates()
     {
         return technicalReplicates;
     }
 
-    public void setTechnicalReplicates(MaterialBiologicalReplicateFeatureSummary defaultReplica)
+    public void setDirectTechnicalReplicates(
+            MaterialBiologicalReplicateFeatureSummary defaultReplica)
     {
         this.technicalReplicates = defaultReplica;
     }
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
index f966bad4db2..d347bdeac9d 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
@@ -95,7 +95,7 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
 
         assertEquals(featuresDesc, featureVectors.getFeatureDescriptions());
         int groupId = 1;
-        for (MaterialBiologicalReplicateFeatureVector subgroup : featureVectors.getSubgroups())
+        for (MaterialBiologicalReplicateFeatureVector subgroup : featureVectors.getBiologicalReplicates())
         {
             switch (groupId)
             {
-- 
GitLab