diff --git a/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java b/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java
index c4f866b891cec69916dbbec20f4f5f9c8d59fe6b..a68f55f00a75326e11ddab8f9a75b038fad82592 100644
--- a/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java
+++ b/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java
@@ -30,6 +30,7 @@ import fr.inrae.po2engine.model.dataModel.StepFile;
 import fr.inrae.po2engine.utils.ProgressPO2;
 import fr.inrae.po2engine.utils.Tools;
 import guru.nidi.graphviz.attribute.Color;
+import guru.nidi.graphviz.attribute.Rank;
 import guru.nidi.graphviz.engine.*;
 import guru.nidi.graphviz.model.Factory;
 import guru.nidi.graphviz.model.MutableGraph;
@@ -70,6 +71,8 @@ import java.io.IOException;
 import java.util.*;
 import java.util.stream.Collectors;
 
+import static guru.nidi.graphviz.attribute.Rank.RankDir.LEFT_TO_RIGHT;
+
 public class ItineraryOverviewController {
 
    @FXML
@@ -271,7 +274,7 @@ public class ItineraryOverviewController {
         prodOfbox.getChildren().addAll(prodLabel, listProduct, graphTips, bbb);
 
         reinitScreen.setOnAction(actionEvent -> {
-            browser.getEngine().reload();
+            browser.getEngine().executeScript("graph.reinit()");
         });
 
         exportImg.setOnAction(actionEvent -> {
@@ -309,7 +312,7 @@ public class ItineraryOverviewController {
     private void generateGraph2(WebView webView, ItineraryFile itiFile, String title, HashMap<Integer, StepFile> listIdStep, HashMap<Integer, CompositionFile> listIdComposition) {
 
 
-        ObservableList<Pair<Pair<ComplexField, ObjectProperty<StepFile>>, Pair<ComplexField, ObjectProperty<StepFile>>>> list = itiFile.getItinerary();
+        ObservableList<Pair<Pair<ComplexField, ObjectProperty<StepFile>>, Pair<ComplexField, ObjectProperty<StepFile>>>> itinerary = itiFile.getItinerary();
             WebEngine webEngine = webView.getEngine();
 
 //            Double width = webView.getWidth();
@@ -324,22 +327,67 @@ public class ItineraryOverviewController {
                 HashMap<String, StepFile> listStep = new HashMap<>();
                 HashMap<StepFile, MutableNode> listStepNode = new HashMap<>();
                 HashMap<CompositionFile, MutableNode> listCompo = new HashMap<>();
+                HashMap<StepFile, MutableGraph> listSubGraph = new HashMap<>();
+
+                final Integer[] nbNode = {444};
+                itiFile.getListStep().filtered(s -> s.getFather() != null).forEach(s -> {
+                    StepFile father = s.getFather();
+                    if(!listStepNode.containsKey(father)) {
+                        MutableNode ms = Factory.mutNode(father.getOntoType() + " (" + father.getId() + ")");
+                        ms.add("id", nbNode[0]);
+                        ms.add("observation", father.getObservationFiles().size());
+                        ms.add("hat", "yes");
+                        listIdStep.put(nbNode[0], father);
+
+                        MutableGraph cluster = Factory.mutGraph(nbNode[0].toString());
+                        cluster.setDirected(true);
+                        cluster.graphAttrs().add(Rank.dir(LEFT_TO_RIGHT));
+                        cluster.setCluster(false);
+                        cluster.add(ms);
+                        cluster.addTo(g);
+                        listSubGraph.put(father, cluster);
+                        listNode.put(father.getOntoType() + " (" + father.getId() + ")", ms);
+                        listStep.put(father.getOntoType() + " (" + father.getId() + ")", father);
+                        listStepNode.put(father, ms);
+                        nbNode[0]++;
+                    }
+                });
 
-                Integer nbNode = 444;
                 for(StepFile s : itiFile.getListStep()) {
-                    MutableNode ms = Factory.mutNode(s.getOntoType() + " (" + s.getId() + ")");
-                    ms.add("id", nbNode);
-                    ms.add("observation", s.getObservationFiles().size());
-                    listIdStep.put(nbNode,s);
-                    nbNode++;
-
-                    listNode.put(s.getOntoType() + " (" + s.getId() + ")", ms);
-                    listStep.put(s.getOntoType() + " (" + s.getId() + ")", s);
-                    listStepNode.put( s, ms);
-                    g.add(ms);
+                    if(!listIdStep.containsValue(s)) {
+                        MutableNode ms = Factory.mutNode(s.getOntoType() + " (" + s.getId() + ")");
+                        ms.add("id", nbNode[0]);
+                        ms.add("observation", s.getObservationFiles().size());
+                        ms.add("hat", "no");
+                        listIdStep.put(nbNode[0],s);
+                        nbNode[0]++;
+
+                        listNode.put(s.getOntoType() + " (" + s.getId() + ")", ms);
+                        listStep.put(s.getOntoType() + " (" + s.getId() + ")", s);
+                        listStepNode.put( s, ms);
+
+                        if(s.getFather() != null) {
+                            listSubGraph.get(s.getFather()).add(ms);
+                        } else {
+                            g.add(ms);
+                        }
+                    }
                 }
 
-                for (Pair<Pair<ComplexField, ObjectProperty<StepFile>>, Pair<ComplexField, ObjectProperty<StepFile>>> pair : list) {
+                // adding link substep
+                listStepNode.keySet().stream().filter(s -> s.getFather() != null).forEach(s -> {
+                    MutableNode p = null;
+                    if(s.getFather() != null) {
+                        p = listNode.get(s.getFather().getOntoType() + " (" + s.getFather().getId() + ")");
+                    }
+                    MutableNode f = null;
+                    f = listNode.get(s.getOntoType() + " (" + s.getId() + ")");
+                    if(p!=null && f!= null) {
+                        p.addLink(f);
+                    }
+                });
+
+                for (Pair<Pair<ComplexField, ObjectProperty<StepFile>>, Pair<ComplexField, ObjectProperty<StepFile>>> pair : itinerary) {
                     MutableNode p = null;
                     if(pair.getKey().getValue().get() != null) {
                         p = listNode.get(pair.getKey().getValue().getValue().getOntoType() + " (" + pair.getKey().getValue().get().getId() + ")");
@@ -349,27 +397,20 @@ public class ItineraryOverviewController {
                         f = listNode.get(pair.getValue().getValue().getValue().getOntoType() + " (" + pair.getValue().getValue().get().getId() + ")");
                     }
 
-                    if (p == null) {
+                    if (p == null || f == null) {
                        // error
                     }
-                    if(p!= null) {
-                     //   g.add(p);
-                    }
-                    if (f == null) {
-//                        error
-                    }
-                    if(f!= null) {
-//                        g.add(f);
-                    }
 
                     if(p!=null && f!= null) {
-                        g.add(p.addLink(f));
+                        p.addLink(f);
                     }
-
                 }
 
                 if(showAllCompo.get()) {
                     for (StepFile sf : listStep.values()) {
+                        if(!sf.getSubStep().isEmpty()) {
+                            System.out.println("break");
+                        }
                         for (Map.Entry<CompositionFile, Boolean> en : sf.getCompositionFile().entrySet()) {
                             MutableNode pc = null;
                             pc = listCompo.get(en.getKey());
@@ -377,9 +418,9 @@ public class ItineraryOverviewController {
                                 pc = Factory.mutNode( en.getKey().getFileName());
                                 pc.add(guru.nidi.graphviz.attribute.Label.of(en.getKey().getCompositionID().getValue().get()));
                                 pc.add(Color.named("red"));
-                                pc.add("id", nbNode);
-                                listIdComposition.put(nbNode, en.getKey());
-                                nbNode++;
+                                pc.add("id", nbNode[0]);
+                                listIdComposition.put(nbNode[0], en.getKey());
+                                nbNode[0]++;
                                 g.add(pc);
                                 listCompo.put(en.getKey(), pc);
                             }
@@ -392,63 +433,15 @@ public class ItineraryOverviewController {
                     }
                 }
 
-                if(showISCompo.get()) {
-                    HashMap<MutableNode, ArrayList<StepFile>> nodeToAddInput = new HashMap<>();
-                    HashMap<MutableNode, ArrayList<StepFile>> nodeToAddOutput = new HashMap<>();
-
-                    for (StepFile sf : listStep.values()) {
-                        for (Map.Entry<CompositionFile, Boolean> en : sf.getCompositionFile().entrySet()) {
-                            MutableNode pc = null;
-                            pc = listCompo.get(en.getKey());
-                            if (pc == null) { // ok premiere fois qu'on la voie
-                                pc = Factory.mutNode( en.getKey().getFileName());
-                                pc.add(guru.nidi.graphviz.attribute.Label.of(en.getKey().getCompositionID().getValue().get()));
-                                pc.add(Color.named("red"));
-                                listCompo.put(en.getKey(), pc);
-                                ArrayList<StepFile> l = new ArrayList<>();
-                                l.add(sf);
-                                if (en.getValue()) {
-                                    nodeToAddInput.put(pc, l);
-                                } else {
-                                    nodeToAddOutput.put(pc, l);                                }
-                            } else {
-                                // compo déjà rencontré
-                                if(en.getValue()) { // input
-                                    if(nodeToAddOutput.containsKey(pc)) { // output -> on supprime
-                                        nodeToAddOutput.remove(pc);
-                                    } else { // on rajoute son nouvel input
-                                        nodeToAddInput.get(pc).add(sf);
-                                    }
-                                } else {
-                                    if(nodeToAddInput.containsKey(pc)) {
-                                        nodeToAddInput.remove(pc);
-                                    } else { // on rajoute son nouvel output
-                                        nodeToAddOutput.get(pc).add(sf);
-                                    }
-                                }
-                            }
-
-                        }
-                    }
-                    nodeToAddInput.forEach((entries, listStepFile) -> {
-                        listStepFile.forEach(stepFile -> {
-                            entries.addLink(listStepNode.get(stepFile));
-                        });
-                        g.add(entries);
-                    });
-                    nodeToAddOutput.forEach((entries, listStepFile) -> {
-                        listStepFile.forEach(stepFile -> {
-                            listStepNode.get(stepFile).addLink(entries);
-                        });
-                        g.add(entries);
-                    });
-                }
-
-
         List<GraphvizEngine> listEngine = new ArrayList<>(
                 Arrays.asList(new GraphvizCmdLineEngine(), new GraphvizV8Engine(), new GraphvizJdkEngine()));
         Graphviz.useEngine(listEngine);
         Graphviz viz = Graphviz.fromGraph(g);
+        try {
+            viz.render(Format.PNG).toFile(new File("/home/stephane/test.png"));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
         String json = viz.render(Format.JSON).toString();
 
         JSONObject jsonGraph = new JSONObject(json);
@@ -459,23 +452,37 @@ public class ItineraryOverviewController {
             Double maxHeaght = 0.0;
             for (Integer i = 0; i < listGraphNode.length(); i++) {
                 JSONObject node = listGraphNode.getJSONObject(i);
-                String[] pos = node.getString("pos").split(",");
-                maxHeaght = Math.max(maxHeaght,Double.valueOf(pos[1]) );
+                if(!node.optString("pos").isEmpty()) {
+                    String[] pos = node.getString("pos").split(",");
+                    maxHeaght = Math.max(maxHeaght,Double.valueOf(pos[1]) );
+                }
             }
             for (Integer i = 0; i < listGraphNode.length(); i++) {
                 JSONObject node = listGraphNode.getJSONObject(i);
-                String[] pos = node.getString("pos").split(",");
-                String label = node.getString("label").replaceAll("\\\\N", "");
-                Double posX = Double.valueOf(pos[0]) - 100.0;
-                Double posY = maxHeaght - (Double.valueOf(pos[1]) - 100.0);
+                if(!node.optString("pos").isEmpty()) {
+                    String[] pos = node.getString("pos").split(",");
+                    String label = node.getString("label").replaceAll("\\\\N", "");
+                    Double posX = Double.valueOf(pos[0]) - 100.0;
+                    Double posY = maxHeaght - (Double.valueOf(pos[1]) - 100.0);
+
+                    if (label.isEmpty()) {
+                        Platform.runLater(() -> {
+                            String type = node.getString("hat").equalsIgnoreCase("yes") ? "hat" : "step";
+                            webEngine.executeScript("graph.addNodeNoUpdate('" + node.getString("name").replaceAll("'", "\\\\'") + "'," + node.getInt("id") + ",'" + type + "', " + node.getInt("observation") + "," + posX + "," + posY + ");");
+                        });
+                    } else {
+                        Platform.runLater(() -> {
 
-                if (label.isEmpty()) {
-                    Platform.runLater(() -> {
-                        webEngine.executeScript("graph.addNodeNoUpdate('" + node.getString("name").replaceAll("'", "\\\\'") + "'," + node.getInt("id") + ",'step', "+ node.getInt("observation")+ "," + posX + "," + posY + ");");
-                    });
+                            webEngine.executeScript("graph.addNodeNoUpdate('" + label.replaceAll("'", "\\\\'") + "'," + node.getInt("id") + ",'composition', 0 ," + posX + "," + posY + ");");
+                        });
+                    }
                 } else {
+                    // cluster node
+                    Double posX = 0.0;
+                    Double posY = 0.0;
+
                     Platform.runLater(() -> {
-                        webEngine.executeScript("graph.addNodeNoUpdate('" + label.replaceAll("'", "\\\\'") + "'," + node.getInt("id") + ",'composition', 0 ," + posX + "," + posY + ");");
+                        webEngine.executeScript("graph.addNodeNoUpdate(''," + -1 + ",'" + "cluster" + "', " + "0" + "," + posX + "," + posY + ");");
                     });
                 }
             }
@@ -486,6 +493,7 @@ public class ItineraryOverviewController {
             for (Integer i = 0; i < listGraphEdge.length(); i++) {
                 JSONObject edge = listGraphEdge.getJSONObject(i);
                 Platform.runLater(() -> {
+                    System.out.println("graph.addEdgeNoUpdate(" + edge.getInt("tail") + "," + edge.getInt("head") + ");");
                     webEngine.executeScript("graph.addEdgeNoUpdate(" + edge.getInt("tail") + "," + edge.getInt("head") + ");");
                 });
             }
diff --git a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.css b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.css
index e391f9060a64ff16745d552f46136a17da6f19e3..f519544cf831913bf6139f59dc99af74d90c3760 100644
--- a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.css
+++ b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.css
@@ -75,6 +75,21 @@ marker{
     fill: #333;
 }
 
+g.conceptG[nodeType=cluster] circle {
+    fill: rgba(255, 255, 255, 0);
+    stroke-width: 0px;
+}
+g.conceptG[nodeType=hat][obs=no] circle{
+    fill: #fff;
+    stroke: url(#hat);
+    stroke-width: 6px;
+}
+g.conceptG[nodeType=hat][obs=yes] circle{
+    fill: #fff;
+    stroke: url(#hatobs);
+    stroke-width: 6px;
+}
+
 g.conceptG[nodeType=step][obs=no] circle{
     fill: #fff;
     stroke: #000;
@@ -97,18 +112,40 @@ g.conceptG:hover[nodeType][obs] circle{
 }
 
 g.selected[nodeType][obs] circle{
-    fill: #ff6464;
+    fill: #a0a0a0;
 }
 g.selected:hover circle{
     fill: #ff6464;
 }
 
+
+
+path.link[linkType=hc]{
+    fill: none;
+    stroke: #ffb941;
+    stroke-width: 6px;
+    cursor: default;
+}
+path.link[linkType=ch]{
+    fill: none;
+    stroke: #ffb941;
+    stroke-width: 6px;
+    cursor: default;
+}
+
 path.link[linkType=ss]{
     fill: none;
     stroke: #000000;
     stroke-width: 6px;
     cursor: default;
 }
+path.link[linkType=hs]{
+    fill: none;
+    stroke: #5593ff;
+    /*stroke: url(#linksc);*/
+    stroke-width: 6px;
+    cursor: default;
+}
 path.link[linkType=sc]{
     fill: none;
     stroke: #ff6464;
@@ -124,6 +161,13 @@ path.link[linkType=cs]{
     cursor: default;
 }
 
+path.link[linkType=drag]{
+    fill: none;
+    stroke: #000000;
+    stroke-width: 6px;
+    cursor: default;
+}
+
 path.link:hover{
     stroke: #53aab1;
 }
@@ -137,5 +181,5 @@ path.link.hidden{
 }
 
 path.link.selected {
-    stroke: #ff6464;
+    stroke: #a0a0a0;
 }
diff --git a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js
index 91a6fc49ccf879c70734f2aa11e0366277f51fa1..345038fe2f6aadd14b9fb9e012b08fa5c75a0cc1 100644
--- a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js
+++ b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js
@@ -61,6 +61,28 @@
       .append('svg:path')
       .attr('d', 'M0,-5L10,0L0,5');
 
+    var grad = defs.append('svg:linearGradient')
+        .attr('id', 'hat')
+    grad.append("svg:stop")
+        .attr("offset","0%")
+        .attr("stop-color","#000000");
+    grad.append("svg:stop")
+        .attr("offset","100%")
+        .attr("stop-color","#5593ff");
+
+
+    var grad = defs.append('svg:linearGradient')
+        .attr('id', 'hatobs')
+    grad.append("svg:stop")
+        .attr("offset","0%")
+        .attr("stop-color","#000000");
+    grad.append("svg:stop")
+        .attr("offset","30%")
+        .attr("stop-color","#5593ff");
+    grad.append("svg:stop")
+        .attr("offset","100%")
+        .attr("stop-color","#51d13a");
+
     var grad = defs.append('svg:linearGradient')
         .attr('id', 'stepobs')
     grad.append("svg:stop")
@@ -96,8 +118,8 @@
         .attr("height", height);
     // displayed when dragging between nodes
     thisGraph.dragLine = svgG.append('svg:path')
-      .attr('class', 'link dragline hidden')
-      .attr('d', 'M0,0L0,0')
+      .attr('class', 'link')
+      .attr('linkType', 'drag')
       .style('marker-end', 'url(#mark-end-arrow)');
 
     // svg nodes and edges 
@@ -424,7 +446,7 @@
 
     thisGraph.dragLine.classed("hidden", true);
 
-    if (mouseDownNode !== d && (mouseDownNode.type === "step" || d.type === "step")) {
+    if (mouseDownNode !== d && ((mouseDownNode.type === "step" || d.type === "step") && (mouseDownNode.type !== "hat" && d.type !== "hat"))) {
       // we're in a different node: create new edge for mousedown edge and add to graph
       var newEdge = {
         source: mouseDownNode,
@@ -534,20 +556,24 @@
         if (selectedNode && selectedNode.type === "composition" && thisGraph.javaFXEditable()) {
  	  alert("Composition can't be removed here");
 	  thisGraph.svgKeyUp(); // force keyup because event is blocked by alert !
-	} else if (selectedNode && selectedNode.type === "step" && thisGraph.javaFXEditable()) {
-	  //alert("Step can't be removed here");
-          //thisGraph.svgKeyUp(); // force keyup because event is blocked by alert !
+	} else if(selectedNode && selectedNode.type === "hat" && thisGraph.javaFXEditable()) {
+          alert("Box step can't be removed here");
+          thisGraph.svgKeyUp(); // force keyup because event is blocked by alert !
+        } else if (selectedNode && selectedNode.type === "step" && thisGraph.javaFXEditable()) {
           thisGraph.javaFXDelNode(selectedNode);
           thisGraph.nodes.splice(thisGraph.nodes.indexOf(selectedNode), 1);
           thisGraph.spliceLinksForNode(selectedNode);
           state.selectedNode = null;
           thisGraph.updateGraph(false);
+        } else if(selectedEdge && selectedEdge.source.type === "hat" && selectedEdge.target.type === "step") {
+          alert("Substep link can't be removed here");
+          thisGraph.svgKeyUp();
         } else if (selectedEdge && thisGraph.javaFXEditable()) {
-          thisGraph.javaFXDelEdge(selectedEdge);
-          thisGraph.edges.splice(thisGraph.edges.indexOf(selectedEdge), 1);
-          state.selectedEdge = null;
-          thisGraph.updateGraph(false);
-        }
+        thisGraph.javaFXDelEdge(selectedEdge);
+        thisGraph.edges.splice(thisGraph.edges.indexOf(selectedEdge), 1);
+        state.selectedEdge = null;
+        thisGraph.updateGraph(false);
+      }
         break;
     }
   };