diff --git a/nb-configuration.xml b/nb-configuration.xml
new file mode 100644
index 0000000000000000000000000000000000000000..29f974656b191f1ed5e7d332dc04185a5950e25a
--- /dev/null
+++ b/nb-configuration.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-shared-configuration>
+    <!--
+This file contains additional configuration written by modules in the NetBeans IDE.
+The configuration is intended to be shared among all the users of project and
+therefore it is assumed to be part of version control checkout.
+Without this configuration present, some functionality in the IDE may be limited or fail altogether.
+-->
+    <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
+        <!--
+Properties that influence various parts of the IDE, especially code formatting and the like. 
+You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
+That way multiple projects can share the same settings (useful for formatting rules for example).
+Any value defined here will override the pom.xml file value but is only applicable to the current project.
+-->
+        <org-netbeans-modules-html-editor-lib.default-html-public-id>HTML5</org-netbeans-modules-html-editor-lib.default-html-public-id>
+    </properties>
+</project-shared-configuration>
diff --git a/pom.xml b/pom.xml
index efe854aea380d4f0cccab76eb66bb82cbfb1c2de..cba28d3e62266772b855069d36bc8de64f63d044 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,8 +62,8 @@
     <packaging>jar</packaging>
 
     <scm>
-        <connection>scm:svn:http://trac.clermont.cemagref.fr/svn/LISC/Observation/tags/observation-0.1.1</connection>
-        <url>http://trac.clermont.cemagref.fr/projets/LISC/browser/Observation/tags/observation-0.1.1</url>
+        <connection>scm:svn:http://trac.clermont.cemagref.fr/svn/LISC/Observation/tags/observation-0.1.4</connection>
+        <url>http://trac.clermont.cemagref.fr/projets/LISC/browser/Observation/tags/observation-0.1.4</url>
     </scm>
     <build>
         <plugins>
diff --git a/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java b/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java
index 5ab47c2ede5d9f3390e7cac2722f5c3adfe658dd..0a5f8aa7160fbb5ad9194f1d9689d1f4a14e467c 100644
--- a/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java
+++ b/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java
@@ -21,90 +21,103 @@ import javax.swing.event.ListSelectionListener;
 @SuppressWarnings("serial")
 public class ObserversManagerPanel extends JPanel implements ListSelectionListener {
 
+    private ObservableManager observableManager;
     private ObserversManagerHandler observersManagerHandler;
     private JList list;
     private JButton removeButton;
     private JButton confButton;
     private JButton showButton;
-   
     private HashSet<ClassAndObserver> observersShowed = new HashSet<ClassAndObserver>();
-    
-    public ObserversManagerPanel(ObserversManagerHandler observersManagerHandler) {
+
+    public ObserversManagerPanel(ObservableManager observableManager, ObserversManagerHandler observersManagerHandler) {
         super();
+        this.observableManager = observableManager;
         this.observersManagerHandler = observersManagerHandler;
-        
+
         this.setLayout(new BorderLayout());
         // The list
-        list = new JList(ObservableManager.getObservableManager());
+        list = new JList(observableManager);
         list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
         list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
         list.addListSelectionListener(this);
         JScrollPane listScroller = new JScrollPane(list);
-        this.add(listScroller,BorderLayout.CENTER);
-        
+        this.add(listScroller, BorderLayout.CENTER);
+
         // The toolbar
         JToolBar toolBar = new JToolBar();
         toolBar.setFloatable(false);
-        add(toolBar,BorderLayout.PAGE_END);
+        add(toolBar, BorderLayout.PAGE_END);
 
         // The "remove" button
-        removeButton = ControlsFactory.makeButton("general/Delete24",new RemoveButtonListener(),"Remove the selected module","Remove");        
+        removeButton = ControlsFactory.makeButton("general/Delete24", new RemoveButtonListener(), "Remove the selected module", "Remove");
         toolBar.add(removeButton);
-        
+
         // The "conf" button
-        confButton = ControlsFactory.makeButton("general/Edit24",new ConfButtonListener(),"Configure the selected module","Configure");        
+        confButton = ControlsFactory.makeButton("general/Edit24", new ConfButtonListener(), "Configure the selected module", "Configure");
         toolBar.add(confButton);
 
         // The "show" button
-        showButton = ControlsFactory.makeButton("general/Find24",new ShowButtonListener(),"Show the selected module","Show");        
+        showButton = ControlsFactory.makeButton("general/Find24", new ShowButtonListener(), "Show the selected module", "Show");
         toolBar.add(showButton);
 
         // set buttons enabled or not
         this.valueChanged(null);
     }
+    
+    public void reloadObservers(ObservableManager observableManager) {
+        this.observableManager = observableManager;
+        list.setModel(observableManager);
+        this.valueChanged(null);
+    }
 
+    @Override
     public void valueChanged(ListSelectionEvent e) {
-        if (list.getSelectedIndex()>=0) {
-            ClassAndObserver classAndObserver = (ClassAndObserver)list.getSelectedValue();
+        if (list.getSelectedIndex() >= 0) {
+            ClassAndObserver classAndObserver = (ClassAndObserver) list.getSelectedValue();
             removeButton.setEnabled(true);
             confButton.setEnabled(classAndObserver.getObserver() instanceof Configurable);
             showButton.setEnabled(
                     // observers must be drawable
                     classAndObserver.getObserver() instanceof Drawable
                     // and observers must not be yet displayed
-                    && !observersShowed.contains(classAndObserver)
-            );
+                    && !observersShowed.contains(classAndObserver));
         } else {
             removeButton.setEnabled(false);
             confButton.setEnabled(false);
             showButton.setEnabled(false);
         }
-        
+
     }
 
     private class RemoveButtonListener implements ActionListener {
+
+        @Override
         public void actionPerformed(ActionEvent e) {
-            if (JOptionPane.showConfirmDialog(observersManagerHandler.getHandlingFrame(),"Sure ?","Confirmation",JOptionPane.YES_NO_OPTION)==0) {
-                ClassAndObserver item = (ClassAndObserver)list.getSelectedValue();
-                ObservableManager.removeObserverListener(item.getType(),item.getObserver());
+            if (JOptionPane.showConfirmDialog(observersManagerHandler.getHandlingFrame(), "Sure ?", "Confirmation", JOptionPane.YES_NO_OPTION) == 0) {
+                ClassAndObserver item = (ClassAndObserver) list.getSelectedValue();
+                observableManager.removeObserverListener(item.getType(), item.getObserver());
             }
         }
     }
 
     private class ConfButtonListener implements ActionListener {
+
+        @Override
         public void actionPerformed(ActionEvent e) {
-            ((Configurable)((ClassAndObserver)list.getSelectedValue()).getObserver()).configure();
+            ((Configurable) ((ClassAndObserver) list.getSelectedValue()).getObserver()).configure();
         }
     }
-    
+
     private class ShowButtonListener implements ActionListener {
+
+        @Override
         public void actionPerformed(ActionEvent e) {
-            ClassAndObserver classAndObserver = (ClassAndObserver)list.getSelectedValue();
+            ClassAndObserver classAndObserver = (ClassAndObserver) list.getSelectedValue();
             if (observersShowed.add(classAndObserver)) {
                 // force buttons enabling refresh
                 valueChanged(null);
                 // get display and add it in handler
-                observersManagerHandler.showDrawable((Drawable)classAndObserver.getObserver());
+                observersManagerHandler.showDrawable((Drawable) classAndObserver.getObserver());
             }
         }
     }
diff --git a/src/main/java/fr/cemagref/observation/kernel/Observable.java b/src/main/java/fr/cemagref/observation/kernel/Observable.java
index c87ab68a61d39ac7ae29899e5cbe2d74b1e4ec03..91d7afc0455a95c953c4b3a53d71432634c19861 100644
--- a/src/main/java/fr/cemagref/observation/kernel/Observable.java
+++ b/src/main/java/fr/cemagref/observation/kernel/Observable.java
@@ -1,6 +1,3 @@
-/**
- *  L'interface "annotation" pour marquer les observables.
- */
 package fr.cemagref.observation.kernel;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -19,4 +16,25 @@ public @interface Observable {
      * @return the textual description of the observable.
      */
     String description();
+    
+    /**
+     * Indicates the size of each dimension of the observable. If a labelsMethod
+     * is provided, the size will be ignored, but the number of dimensions is needed.
+     * 
+     * @return 
+     */
+    int[] size() default {};
+    
+    /**
+     * Indicates the name of the method to invoke for having the labels of the data.
+     * It is usefull, when the size of the data vector isn't a constant, but can be
+     * retrieved programmaticaly.
+     * 
+     * The target method must accept a single <tt>Integer</tt> argument that is the dimension
+     * concerned. For example, if your observed data is a matrix (dimension 2), you should
+     * give "{0,0}" as size, and your method will return an array of labels for each dimension.
+     * 
+     * @return 
+     */
+    String labelsMethod() default "";
 }
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java
index 76cb0b3ee3a285c7aa6f02ca1ef8c6fc4c4434bb..77d26fc2b2b6bb245a916ef019b8e82e26388e6a 100644
--- a/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java
+++ b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java
@@ -2,7 +2,6 @@ package fr.cemagref.observation.kernel;
 
 import java.io.Reader;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -14,40 +13,26 @@ import javax.swing.event.ListDataListener;
 
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.io.xml.DomDriver;
+import java.util.HashMap;
 
-/**
- * TODO traduce in english
- */
 public class ObservableManager implements ListModel {
 
     private static ObservableManager om = null;
     private Map<Class, ObservablesHandler> observables;
     private List<ListDataListener> listDataListeners = new ArrayList<ListDataListener>();
 
-    /** Le constructeur. Il est private, car l'accès à l'observable manager doit
-     * se faire exclusivement via la méthode statique getObservableManager().
-     */
-    private ObservableManager() {
-		observables = new Hashtable<Class,ObservablesHandler>();
-    }
-
-    /**
-     * The true mean to access Observable manager.
-     *
-     * @return L'observable manager du système.
-     */
-    public static ObservableManager getObservableManager() {
-        return om == null ? om = new ObservableManager() : om;
+    public ObservableManager() {
+        observables = new HashMap<Class, ObservablesHandler>();
     }
 
     /**
      * clear method clears all class-observers associations
      */
-    public static void clear() {
-        for (ObservablesHandler co : om.observables.values()) {
+    public void clear() {
+        for (ObservablesHandler co : observables.values()) {
             co.clearObservers();
         }
-        om.fireObservableManagerStructureChanged();
+        fireObservableManagerStructureChanged();
     }
 
     /**
@@ -59,13 +44,13 @@ public class ObservableManager implements ListModel {
      * @param cl La classe déclarée comme observable
      * @return Le ClassObservable de cl.
      */
-    public static ObservablesHandler addObservable(Class cl) {
-        if (getObservableManager().observables.containsKey(cl)) {
-            return getObservableManager().observables.get(cl);
+    public ObservablesHandler addObservable(Class cl) {
+        if (observables.containsKey(cl)) {
+            return observables.get(cl);
         }
         ObservablesHandler co = new ObservablesHandler(cl);
-        getObservableManager().observables.put(cl, co);
-        getObservableManager().fireObservableManagerStructureChanged();
+        observables.put(cl, co);
+        fireObservableManagerStructureChanged();
         return co;
     }
 
@@ -83,17 +68,17 @@ public class ObservableManager implements ListModel {
      * @return Le classObservable, ou null si la classe donnée en argument
      * n'a pas été déclarée comme étant observable.
      */
-    public static ObservablesHandler getObservable(Class cl) {
-        return getObservableManager().observables.get(cl);
+    public ObservablesHandler getObservable(Class cl) {
+        return observables.get(cl);
     }
 
     /** Ajoute un ObserverListener à la liste.
      * 
      * @param ob L'ObserverListener à ajouter.
      */
-    public static ObserverListener addObserverListener(Class cl, ObserverListener ob) {
+    public ObserverListener addObserverListener(Class cl, ObserverListener ob) {
         ObserverListener observerListener = addObservable(cl).addObserverListener(ob);
-        getObservableManager().fireObservableManagerStructureChanged();
+        fireObservableManagerStructureChanged();
         return observerListener;
     }
 
@@ -102,21 +87,21 @@ public class ObservableManager implements ListModel {
      * @param ob L'ObserverListener à retirer. 
      * @return
      */
-    public static boolean removeObserverListener(Class cl, ObserverListener ob) {
-        boolean response = getObservable(cl).removeObserverListener(ob);
-        getObservableManager().fireObservableManagerStructureChanged();
+    public boolean removeObserverListener(Class cl, ObserverListener ob) {
+        boolean response = getObservable(cl).removeObserverListener(this, ob);
+        fireObservableManagerStructureChanged();
         return response;
     }
 
-    public static void initObservers() {
-        for (ObservablesHandler classObservable : getObservableManager().observables.values()) {
+    public void initObservers() {
+        for (ObservablesHandler classObservable : observables.values()) {
             for (ObserverListener observer : classObservable.getObservers()) {
                 observer.init();
             }
         }
     }
 
-    public static void closeObservers() {
+    public void closeObservers() {
         for (ObservablesHandler classObservable : getObservables().values()) {
             for (ObserverListener observer : classObservable.getObservers()) {
                 observer.close();
@@ -124,13 +109,13 @@ public class ObservableManager implements ListModel {
         }
     }
 
-    public static Map<Class, ObservablesHandler> getObservables() {
-        return getObservableManager().observables;
+    public Map<Class, ObservablesHandler> getObservables() {
+        return observables;
     }
 
-    public static void setObservers(Reader observablesReader, XStream xstream) {
-        Map<Class,ObservablesHandler> observablesReaded = (Map<Class,ObservablesHandler>) xstream.fromXML(observablesReader);
-        for (Map.Entry<Class,ObservablesHandler> entry : observablesReaded.entrySet()) {
+    public void setObservers(Reader observablesReader, XStream xstream) {
+        Map<Class, ObservablesHandler> observablesReaded = (Map<Class, ObservablesHandler>) xstream.fromXML(observablesReader);
+        for (Map.Entry<Class, ObservablesHandler> entry : observablesReaded.entrySet()) {
             // add to the list of observers those readed from the file
             ObservablesHandler clObservable = addObservable(entry.getKey());
             for (ObserverListener observer : entry.getValue().getObservers()) {
@@ -140,13 +125,14 @@ public class ObservableManager implements ListModel {
         }
     }
 
-    public static void setObservers(Reader observablesReader) {
+    public void setObservers(Reader observablesReader) {
         setObservers(observablesReader, new XStream(new DomDriver()));
     }
 
     /**
      * @see javax.swing.ListModel#getSize()
      */
+    @Override
     public int getSize() {
         int size = 0;
         for (ObservablesHandler classObservable : observables.values()) {
@@ -158,6 +144,7 @@ public class ObservableManager implements ListModel {
     /**
      * @see javax.swing.ListModel#getElementAt(int)
      */
+    @Override
     public Object getElementAt(int index) {
         Set<Map.Entry<Class, ObservablesHandler>> entrySet = observables.entrySet();
         Iterator<Map.Entry<Class, ObservablesHandler>> iterator = entrySet.iterator();
@@ -179,6 +166,7 @@ public class ObservableManager implements ListModel {
     /**
      * @see javax.swing.ListModel#addListDataListener(javax.swing.event.ListDataListener)
      */
+    @Override
     public void addListDataListener(ListDataListener l) {
         listDataListeners.add(l);
     }
@@ -186,6 +174,7 @@ public class ObservableManager implements ListModel {
     /**
      * @see javax.swing.ListModel#removeListDataListener(javax.swing.event.ListDataListener)
      */
+    @Override
     public void removeListDataListener(ListDataListener l) {
         listDataListeners.remove(l);
     }
@@ -214,8 +203,9 @@ public class ObservableManager implements ListModel {
             return observer;
         }
 
+        @Override
         public String toString() {
-            return observer.getClass().getSimpleName() + " -> " + type.getSimpleName();
+            return type.getSimpleName() + " -> " + observer.toString() ;
         }
 
         /**
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java
index 98a805408960c0b9a34c6feff4ef11e375827929..5809a30e7e725f71d6fbcbf01ed9c6e8e8333a0c 100644
--- a/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java
+++ b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java
@@ -5,8 +5,11 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 // TODO troduce in english
 public class ObservablesHandler {
@@ -163,9 +166,9 @@ public class ObservablesHandler {
      * @param ob L'ObserverListener à retirer. 
      * @return
      */
-    public boolean removeObserverListener(ObserverListener ob) {
+    public boolean removeObserverListener(ObservableManager observableManager, ObserverListener ob) {
         boolean response = observers.remove(ob);
-        ObservableManager.getObservableManager().fireObservableManagerStructureChanged();
+        observableManager.fireObservableManagerStructureChanged();
         return response;
     }
 
@@ -217,9 +220,78 @@ public class ObservablesHandler {
         public abstract Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException,
                 InvocationTargetException;
 
+        public Object fetchValueOrNull(Object instance) {
+            try {
+                return fetchValue(instance);
+            } catch (IllegalArgumentException ex) {
+                Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex);
+                return null;
+            } catch (IllegalAccessException ex) {
+                Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex);
+                return null;
+            } catch (InvocationTargetException ex) {
+                Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex);
+                return null;
+            }
+        }
+
+        /**
+         * Return the size of each dimension. If a "labelsMethod" is declared, it will be used, otherwise, the given sizes will be returned. See the @Observable documentation.
+         * @param instance
+         * @return
+         * @throws NoSuchMethodException
+         * @throws IllegalAccessException
+         * @throws IllegalArgumentException
+         * @throws InvocationTargetException 
+         */
+        public int[] getSizes(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+            int[] sizes;
+            if (getLabelsMethod().length() > 0) {
+                sizes = new int[getSize().length];
+                for (int i = 0; i < sizes.length; i++) {
+                    String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i);
+                    sizes[i] = (localLabels).length;
+                }
+            } else {
+                sizes = getSize();
+            }
+            return sizes;
+        }
+
+        public List<String>[] getLabels(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+            List<String>[] labels = new List[getSize().length];
+            if (getLabelsMethod().length() > 0) {
+                for (int i = 0; i < getSize().length; i++) {
+                    String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i);
+                    labels[i] = Arrays.asList(localLabels);
+                }
+            } else {
+                for (int i = 0; i < getSize().length; i++) {
+                    labels[i] = new ArrayList<String>(getSize()[i]);
+                    labels[i].add(getDeclaredName() + "[0]");
+                    for (int j = 1; j < getSize()[i]; j++) {
+                        labels[i].add("[" + j + "]");
+                    }
+                }
+            }
+            return labels;
+        }
+
+        public abstract Observable getAnnotation();
+
         public abstract String getDeclaredName();
 
-        public abstract String getDescription();
+        public String getDescription() {
+            return getAnnotation().description();
+        }
+
+        protected final int[] getSize() {
+            return getAnnotation().size();
+        }
+
+        public String getLabelsMethod() {
+            return getAnnotation().labelsMethod();
+        }
 
         public abstract Class getDeclaredType();
     }
@@ -241,8 +313,8 @@ public class ObservablesHandler {
         }
 
         @Override
-        public String getDescription() {
-            return method.getAnnotation(Observable.class).description();
+        public Observable getAnnotation() {
+            return method.getAnnotation(Observable.class);
         }
 
         @Override
@@ -272,8 +344,8 @@ public class ObservablesHandler {
         }
 
         @Override
-        public String getDescription() {
-            return field.getAnnotation(Observable.class).description();
+        public Observable getAnnotation() {
+            return field.getAnnotation(Observable.class);
         }
 
         @Override
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java b/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java
index 597a9ff6129ad6b8de11493fc2da095d89bd8a3c..3cb877962335e2f39a8a87a21de27da3135e8438 100644
--- a/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java
+++ b/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java
@@ -1,36 +1,38 @@
 package fr.cemagref.observation.kernel;
 
-public interface ObserverListener {
+public abstract class ObserverListener {
+
     /**
      * <code>addObservable</code> is called when an observable is connected to
      * this observable. It gives the possibility to make some init tasks.
-     * 
-     * @param classObservable
-     *            The new observable connected to this observer
+     *
+     * @param classObservable The new observable connected to this observer
      */
-    public void addObservable(ObservablesHandler classObservable);
+    public abstract void addObservable(ObservablesHandler classObservable);
 
     /**
-     * <code>valueChanged</code> is invoked when the observable has updated
-     * its value. It's time for the observer to do its job.
-     * 
-     * @param clObservable
-     *            the observable handler
-     * @param instance
-     *            the observable object
-     * @param t
-     *            the current time
+     * <code>valueChanged</code> is invoked when the observable has updated its
+     * value. It's time for the observer to do its job.
+     *
+     * @param clObservable the observable handler
+     * @param instance the observable object
+     * @param t the current time
      */
-    public void valueChanged(ObservablesHandler clObservable, Object instance, long t);
+    public abstract void valueChanged(ObservablesHandler clObservable, Object instance, long t);
 
     /**
      * <code>init</code> Called at begin of simulation
      */
-    public void init();
+    public abstract void init();
 
     /**
      * <code>close</code> Called at end of simulation
-     * 
+     *
      */
-    public void close();
+    public abstract void close();
+
+    @Override
+    public String toString() {
+        return this.getClass().getSimpleName();
+    }
 }
diff --git a/src/main/java/fr/cemagref/observation/observers/CSVObserver.java b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java
index 3791290d8e03fe3362f7da1fdcde11e5cec8c70c..5f321d350c7f13a50bb8ad588a2d0b0b1e4c7955 100644
--- a/src/main/java/fr/cemagref/observation/observers/CSVObserver.java
+++ b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java
@@ -4,67 +4,119 @@ import java.lang.reflect.InvocationTargetException;
 
 import fr.cemagref.observation.kernel.ObservablesHandler;
 import fr.cemagref.ohoui.annotations.Description;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 public class CSVObserver extends ConsoleObserver {
 
-    @Description(name="Field separator", tooltip="")
-    private char separator = ';';
-    
-    /** <code>classObservable</code> is used to display name of attributes as header */
+    @Description(name = "Field separator", tooltip = "")
+    protected char separator = ';';
+    private List<String> observables;
+    protected transient List<ObservablesHandler.ObservableFetcher> fetchers;
+    /**
+     * <code>classObservable</code> is used to display name of attributes as
+     * header
+     */
     private transient ObservablesHandler classObservable;
 
+    public CSVObserver() {
+    }
+
     public CSVObserver(boolean sysout, String outputFile) {
         super(sysout, outputFile);
     }
-    
+
+    public CSVObserver(boolean sysout, String outputFile, String... obsvervables) {
+        super(sysout, outputFile);
+        this.observables = Arrays.asList(obsvervables);
+    }
+
+    public List<String> getObservables() {
+        return observables;
+    }
+
     @Override
     public void addObservable(ObservablesHandler classObservable) {
         ObservablesHandler bak = this.classObservable;
         this.classObservable = classObservable;
         if (bak != null) // The observable has been changed 
+        {
             this.init();
+        }
     }
 
     @Override
     public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
-        StringBuffer buf = new StringBuffer();
-        StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" ");
-        // print current Time
-        buf.append(t);
-        // print value of each field
-        for (int i =0;i<clObservable.numberOfAttributes();i++) {
-            buf.append(sbSeparator);
-            try {
-                buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
-            } catch (IllegalArgumentException e) {
-                buf.append("N/A");
-                e.printStackTrace();
-            } catch (IllegalAccessException e) {
-                buf.append("N/A");
-                e.printStackTrace();
-            } catch (InvocationTargetException e) {
-    			e.printStackTrace();
-                return;
+        if (isInDates(t)) {
+            StringBuffer buf = new StringBuffer();
+            StringBuffer sbSeparator = new StringBuffer(" " + this.separator + " ");
+            // print current Time
+            buf.append(t);
+            // print value of each field
+            for (ObservablesHandler.ObservableFetcher fetcher : fetchers) {
+                buf.append(sbSeparator);
+                Object value = getValue(fetcher, instance);
+                buf.append(value == null ? "N/A" : value);
             }
+            outputStream.println(buf);
+        }
+    }
+
+    /**
+     *
+     * @param fetcher
+     * @param instance
+     * @return the value returned by the fetcher or null if a problem has
+     * occured due to the introspection.
+     */
+    protected Object getValue(ObservablesHandler.ObservableFetcher fetcher, Object instance) {
+        try {
+            return fetcher.fetchValue(instance);
+        } catch (IllegalArgumentException ex) {
+            Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex);
+            return null;
+        } catch (IllegalAccessException ex) {
+            Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex);
+            return null;
+        } catch (InvocationTargetException ex) {
+            Logger.getLogger(CSVObserver.class.getName()).log(Level.SEVERE, null, ex);
+            return null;
         }
-        outputStream.println(buf);
     }
 
     @Override
     public void init() {
         super.init();
         if (classObservable != null) {
+            fetchers = new ArrayList<ObservablesHandler.ObservableFetcher>();
+            if (observables != null) {
+                for (String name : observables) {
+                    fetchers.add(classObservable.getObservableFetcherByName(name));
+                }
+            } else {
+                fetchers.addAll(Arrays.asList(classObservable.getObservableFetchers()));
+            }
             // Headers printing
             StringBuffer buf = new StringBuffer();
-            StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" ");
+            StringBuffer sbSeparator = new StringBuffer(" " + this.separator + " ");
             buf.append("Time");
-            for (int i =0;i<classObservable.numberOfAttributes();i++) {
+            for (ObservablesHandler.ObservableFetcher fetcher : fetchers) {
                 buf.append(sbSeparator);
-                buf.append(classObservable.getDescription(i));
+                buf.append(fetcher.getDescription());
             }
             outputStream.println(buf);
         }
     }
-    
-    
+
+    @Override
+    public String toString() {
+        if (observables != null) {
+        return observables.toString() + " " + super.toString();
+        } else {
+            return super.toString();
+        }
+    }
 }
diff --git a/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java
index 0a8af0a0bda8819bb912d9e35fc3377ce9c4665a..963cb4791df9c8bf63e7908621b8d0cc8da43008 100644
--- a/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java
+++ b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java
@@ -17,63 +17,76 @@ import fr.cemagref.ohoui.swing.OhOUI;
 import fr.cemagref.ohoui.swing.OhOUIDialog;
 import java.io.BufferedOutputStream;
 import java.io.FileOutputStream;
+import java.util.List;
 
-public class ConsoleObserver implements ObserverListener, Configurable {
+public class ConsoleObserver extends ObserverListener implements Configurable {
 
-    @Description(name="Use standard output",tooltip = "")
-    @Link(action="disable",target="filename")
+    @Description(name = "Use standard output", tooltip = "")
+    @Link(action = "disable", target = "filename")
     private boolean sysout = true;
-    
-    @Anchor(id="filename")
+    @Anchor(id = "filename")
     private File outputFile = new File("");
-    
     private transient File outputFileBak = outputFile;
     protected transient PrintStream outputStream = System.out;
+    private List<Integer> dates;
+
+    public ConsoleObserver() {
+    }
 
     public ConsoleObserver(boolean sysout, String outputFile) {
         this.sysout = sysout;
         this.outputFile = new File(outputFile);
         this.init();
     }
-    
+
     @Override
     public void addObservable(ObservablesHandler classObservable) {
         // nothing to do
     }
 
+    protected boolean isInDates(long date) {
+        return dates == null || dates.contains((int) date);
+    }
+
     @Override
     public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
-        StringBuffer buf = new StringBuffer(t+" "+instance.getClass().getName() + " :\n");
-        for (int i =0;i<clObservable.numberOfAttributes();i++) {
-            buf.append("  "+clObservable.getDescription(i)+" = ");
-            try {
-                buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
-            } catch (IllegalArgumentException e) {
-                e.printStackTrace();
-            } catch (IllegalAccessException e) {
-                e.printStackTrace();
-            } catch (InvocationTargetException e) {
-    			e.printStackTrace();
-                return;
+        if (isInDates(t)) {
+            StringBuffer buf = new StringBuffer(t + " " + instance.getClass().getName() + " :\n");
+            for (int i = 0; i < clObservable.numberOfAttributes(); i++) {
+                buf.append("  " + clObservable.getDescription(i) + " = ");
+                try {
+                    buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                } catch (InvocationTargetException e) {
+                    e.printStackTrace();
+                    return;
+                }
+                if (i < clObservable.numberOfAttributes() - 1) {
+                    buf.append("\n");
+                }
             }
-            if (i<clObservable.numberOfAttributes()-1) buf.append("\n");
+            outputStream.println(buf);
         }
-        outputStream.println(buf);
     }
 
     protected void println(CharSequence message) {
         if (sysout) {
-            outputStream.print(this.getClass().getSimpleName()+" :: ");
+            outputStream.print(this.getClass().getSimpleName() + " :: ");
         }
         outputStream.println(message);
     }
-        
+
     @Override
     public void configure() {
-        OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField());
+        OhOUIDialog dialog = OhOUI.getDialog(null, this, new NoTransientField());
         dialog.setSize(new Dimension(510, 160));
         dialog.setVisible(true);
-        if (!outputFile.equals(outputFileBak)) init();
+        if (!outputFile.equals(outputFileBak)) {
+            init();
+        }
         outputFileBak = outputFile;
     }
 
@@ -83,20 +96,29 @@ public class ConsoleObserver implements ObserverListener, Configurable {
             outputStream = System.out;
         } else {
             try {
+                File outputDir = outputFile.getParentFile();
+                if (!outputDir.exists()) {
+                    outputDir.mkdirs();
+                }
                 // it's rather better to use a buffetred outputstream, and to disable to default buffer of the PrintStream
                 outputStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile), 1024), false);
             } catch (FileNotFoundException e) {
-            	// TODO bring info to the user. Or prevent exception when directory of file doesn't exist
+                // TODO bring info to the user. Or prevent exception when directory of file doesn't exist
                 e.printStackTrace();
                 outputStream = System.out;
             }
-        }    
+        }
     }
 
     @Override
     public void close() {
-        if (outputStream != System.out)
+        if (outputStream != System.out) {
             outputStream.close();
+        }
     }
 
+    @Override
+    public String toString() {
+        return "in " + outputFile;
+    }
 }
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java
index 709447d5e1771e4a623e0b0dbd6826c464e78845..1b1d528361a9ac079e1dc5d1a3ba2b4d5fd8ee35 100644
--- a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java
@@ -18,18 +18,19 @@ import fr.cemagref.ohoui.swing.OUIPanel;
 import fr.cemagref.ohoui.swing.OhOUI;
 import fr.cemagref.ohoui.swing.OhOUIDialog;
 
-public abstract class TemporalChart implements ObserverListener, Configurable, Drawable {
+public abstract class TemporalChart extends ObserverListener implements Configurable, Drawable {
 
     private transient ChartPanel chartPanel;
     private transient JFreeChart jfchart;
     protected transient XYSeriesCollection dataset;
     protected GraphType graphType = GraphType.LINE;
+    protected String variableName;
     /**
      * <code>variable</code> is the variable to represent
      */
     protected transient ObservablesHandler.ObservableFetcher variable;
     protected transient ObservablesHandler classObservable;
-    private String title = "", xAxisLabel = "Time", yAxisLabel = "";
+    private String titlePrefix="Observation of ", title = "", xAxisLabel = "Time", yAxisLabel = "";
 
     public TemporalChart() {
         graphTypeUpdated();
@@ -43,11 +44,20 @@ public abstract class TemporalChart implements ObserverListener, Configurable, D
 
     protected void variableUpdated() {
         if (variable != null) {
+            variableName = variable.getDeclaredName();
             yAxisLabel = variable.getDescription();
-            title = "Observation of " + yAxisLabel;
+            title = titlePrefix + yAxisLabel;
         }
     }
 
+    /**
+     * Modify the prefix used for updating the title. By default, it is "Observation of ".
+     * @param prefix
+     */
+    protected void setTitlePrefix(String prefix) {
+        this.titlePrefix = prefix;
+    }
+
     protected void graphTypeUpdated() {
         PlotOrientation orientation = PlotOrientation.VERTICAL;
         boolean legend = true;
@@ -128,11 +138,20 @@ public abstract class TemporalChart implements ObserverListener, Configurable, D
     public void init() {
         if (variable == null) {
             if (classObservable != null) {
-                if (classObservable.numberOfAttributes() > 0) {
+                if (variableName!=null) {
+                    variable = classObservable.getObservableFetcherByName(variableName);
+                } else if (classObservable.numberOfAttributes() > 0) {
                     variable = classObservable.getObservableFetcher(0);
                 }
             }
             // TODO classObservable.getAttributes().length *must* be > 0
         }
     }
+
+    @Override
+    public String toString() {
+        return "Chart: " + title;
+    }
+    
+    
 }
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java
new file mode 100644
index 0000000000000000000000000000000000000000..9abd330566dd98d29706313a76c3109942c48071
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TwoObservablesChart.java
@@ -0,0 +1,247 @@
+/*
+ *  Copyright (C) 2010 Cemagref
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package fr.cemagref.observation.observers.jfreechart;
+
+import fr.cemagref.observation.gui.Configurable;
+import fr.cemagref.observation.gui.Drawable;
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.observation.kernel.ObserverListener;
+import fr.cemagref.ohoui.filters.NoTransientField;
+import fr.cemagref.ohoui.swing.OUIPanel;
+import fr.cemagref.ohoui.swing.OhOUI;
+import fr.cemagref.ohoui.swing.OhOUIDialog;
+import java.lang.reflect.InvocationTargetException;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ *
+ * @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr>
+ */
+public class TwoObservablesChart extends ObserverListener implements Configurable, Drawable {
+
+    private transient ChartPanel chartPanel;
+    private transient JFreeChart jfchart;
+    protected transient XYSeriesCollection dataset;
+    protected GraphType graphType = GraphType.LINE;
+    protected String variableXName;
+    protected String variableYName;
+    protected transient ObservablesHandler.ObservableFetcher variableX;
+    protected transient ObservablesHandler.ObservableFetcher variableY;
+    protected transient ObservablesHandler classObservable;
+    private String titlePrefix = "Observation of ", title = "", xAxisLabel = "", yAxisLabel = "";
+
+    public TwoObservablesChart() {
+        super();
+        graphTypeUpdated();
+    }
+
+    public TwoObservablesChart(ObservablesHandler.ObservableFetcher variableX, ObservablesHandler.ObservableFetcher variableY) {
+        this();
+        this.variableX = variableX;
+        this.variableY = variableY;
+        variablesUpdated();
+        init();
+        dataset = new XYSeriesCollection();
+        graphTypeUpdated();
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#valueChanged(fr.cemagref.observation.kernel.ObservablesHandler, java.lang.Object, int)
+     */
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        System.err.println("Value changed");
+        // we fetch the value of the observable
+        double valueX;
+        double valueY;
+        try {
+            Object objectValue = variableX.fetchValue(instance);
+            if (objectValue instanceof Integer) {
+                valueX = (Integer) objectValue;
+            } else {
+                valueX = (Double) objectValue;
+            }
+            objectValue = variableY.fetchValue(instance);
+            if (objectValue instanceof Integer) {
+                valueY = (Integer) objectValue;
+            } else {
+                valueY = (Double) objectValue;
+            }
+        } catch (IllegalArgumentException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (IllegalAccessException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+            return;
+        }
+        int index = dataset.indexOf(instance.hashCode());
+        XYSeries serie;
+        if (index >= 0) {
+            serie = dataset.getSeries(index);
+        } else {
+            // This is the first value of the observable
+            serie = new XYSeries(instance.hashCode());
+            dataset.addSeries(serie);
+        }
+        System.err.println("hc : " + instance.hashCode());
+        System.err.println("Appending (" + valueX + "," + valueY + ") on " + serie);
+        serie.add(valueX, valueY);
+    }
+
+    protected void variablesUpdated() {
+        if (variableX != null) {
+            variableXName = variableX.getDeclaredName();
+            xAxisLabel = variableX.getDescription();
+        }
+        if (variableY != null) {
+            variableYName = variableY.getDeclaredName();
+            yAxisLabel = variableY.getDescription();
+            title = titlePrefix + yAxisLabel;
+        }
+    }
+
+    /**
+     * Modify the prefix used for updating the title. By default, it is "Observation of ".
+     * @param prefix
+     */
+    protected void setTitlePrefix(String prefix) {
+        this.titlePrefix = prefix;
+    }
+
+    protected void graphTypeUpdated() {
+        PlotOrientation orientation = PlotOrientation.VERTICAL;
+        boolean legend = true;
+        boolean tooltips = true;
+        boolean urls = false;
+
+        if (graphType.equals(GraphType.POINT)) {
+            jfchart = ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.LINE)) {
+            jfchart = ChartFactory.createXYLineChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.AREA)) {
+            jfchart = ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.STEP)) {
+            jfchart = ChartFactory.createXYStepChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.AREASTEP)) {
+            jfchart = ChartFactory.createXYStepAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        }
+        if (chartPanel == null) {
+            chartPanel = new ChartPanel(jfchart);
+        } else {
+            chartPanel.setChart(jfchart);
+        }
+    }
+
+    public JFreeChart getJfchart() {
+        return jfchart;
+    }
+
+    @Override
+    public void configure() {
+        OhOUIDialog dialog = OhOUI.getDialog(null, this, new NoTransientField());
+        // X
+        ObservablesHandler.ObservableFetcher variableXBak = variableX;
+        JComboBox comboBoxX = new JComboBox(classObservable.getDescriptions());
+        if (variableX != null) {
+            comboBoxX.setSelectedItem(variableX.getDescription());
+        }
+        OUIPanel ouiPanel = OUIPanel.makeLabelComponentOUIPanel(variableX, comboBoxX, "Variable for X", "");
+        dialog.getContentPane().add(ouiPanel.getPanel(), 0);
+        // Y
+        ObservablesHandler.ObservableFetcher variableYBak = variableY;
+        JComboBox comboBoxY = new JComboBox(classObservable.getDescriptions());
+        if (variableY != null) {
+            comboBoxY.setSelectedItem(variableY.getDescription());
+        }
+        ouiPanel = OUIPanel.makeLabelComponentOUIPanel(variableY, comboBoxY, "Variable for Y", "");
+        dialog.getContentPane().add(ouiPanel.getPanel(), 1);
+        // pack
+        dialog.pack();
+        dialog.setVisible(true);
+        variableX = classObservable.getObservableFetcher((String) comboBoxX.getSelectedItem());
+        if (variableX != null) {
+            if (!variableX.equals(variableXBak)) {
+                variablesUpdated();
+            }
+        }
+        variableY = classObservable.getObservableFetcher((String) comboBoxY.getSelectedItem());
+        if (variableY != null) {
+            if (!variableY.equals(variableYBak)) {
+                variablesUpdated();
+            }
+        }
+        graphTypeUpdated();
+    }
+
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        this.classObservable = classObservable;
+    }
+
+    @Override
+    public JComponent getDisplay() {
+        return chartPanel;
+    }
+
+    @Override
+    public String getTitle() {
+        return title;
+    }
+
+    @Override
+    public void init() {
+        if (variableX == null) {
+            if (classObservable != null) {
+                if (variableXName != null) {
+                    variableX = classObservable.getObservableFetcherByName(variableXName);
+                } else if (classObservable.numberOfAttributes() > 0) {
+                    variableX = classObservable.getObservableFetcher(0);
+                }
+            }
+            dataset = new XYSeriesCollection();
+            graphTypeUpdated();
+        }
+        if (variableY == null) {
+            if (classObservable != null) {
+                if (variableYName != null) {
+                    variableY = classObservable.getObservableFetcherByName(variableYName);
+                } else if (classObservable.numberOfAttributes() > 1) {
+                    variableY = classObservable.getObservableFetcher(1);
+                }
+            }
+            dataset = new XYSeriesCollection();
+            graphTypeUpdated();
+        }
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#close()
+     */
+    @Override
+    public void close() {
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java
index e96691e5c73cc17f6cdbc42c6fab2f96fbc1b229..c5e571acb1300a3e6c597c352794949942fc324e 100644
--- a/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java
@@ -24,7 +24,7 @@ import java.util.ArrayList;
 import java.util.List;
 import org.jfree.data.xy.XYDataset;
 
-public class XYSeriesChart implements ObserverListener, Configurable, Drawable {
+public class XYSeriesChart extends ObserverListener implements Configurable, Drawable {
 
     private transient ChartPanel chartPanel;
     private transient JFreeChart jfchart;
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
new file mode 100644
index 0000000000000000000000000000000000000000..10ed0f5b3058728f94b7db70adadd6f997f06ce1
--- /dev/null
+++ b/src/main/javadoc/overview.html
@@ -0,0 +1,22 @@
+<html>
+    <body>
+        <p>Observation is a tool for declaring variables and method that can then
+            be connected to an observer that will process these data on demand.</p>
+        
+        <h2>Declaration of an observable</h2>
+        By declaring an observable, you will explicitly say that a field or a method
+        can be retrieved to get an information on your system. Declaring an observable is
+        accomplished by adding the Observable annotation on a field or a method, as in this example:
+        <pre>
+public class Individual {
+  &#064;Observable(description = "age in weeks")
+  private short age;
+  // …
+        </pre>
+        <h2>Use an observer</h2>
+        <h2>Create your own observer</h2>
+        <h2>Notification of an observable update</h2>
+        It can be done by invoking the method fireChanges of the Observable object, for example:
+        <pre>ObservableManager.getObservable(Individual.class).fireChanges(instance,time);</pre>
+    </body>
+</html>
\ No newline at end of file