diff --git a/lang/en/vpl.php b/lang/en/vpl.php
index 1cb1e084d1b60a0964ba3992f7735361bc561ca6..3fc71bb31153fab287cb9af845fa541cea19fb57 100644
--- a/lang/en/vpl.php
+++ b/lang/en/vpl.php
@@ -100,6 +100,8 @@ $string ['filenotrenamed'] = 'The \'{$a}\' file has NOT been renamed';
 $string ['filerenamed'] = "The '{\$a->from}' file has been renamed to '{\$a->to}'";
 $string ['filesChangedNotSaved'] = 'Files have changed but they have not been saved';
 $string ['filesNotChanged'] = 'Files have not changed';
+$string ['filesdiffevolution'] = 'Files diff with required files evolution';
+$string ['filessizeevolution'] = 'Files size evolution';
 $string ['filestoscan'] = 'Files to scan';
 $string ['fileupdated'] = "The '{\$a}' file has been updated";
 $string ['finalreduction'] = 'Final reduction';
diff --git a/locallib.php b/locallib.php
index 9c92e2abf4e7d2bd1eb4d28acb9c1354c416a88c..33fb15fe1afbfd4ee3448432c515a0c968fdc938 100644
--- a/locallib.php
+++ b/locallib.php
@@ -849,7 +849,7 @@ function vpl_get_version() {
     static $version;
     if (! isset( $version )) {
         $plugin = new stdClass();
-        require_once(dirname( __FILE__ ) . '/version.php');
+        require(dirname( __FILE__ ) . '/version.php');
         $version = $plugin->release;
     }
     return $version;
@@ -936,3 +936,7 @@ function vpl_get_webservice_urlbase($vpl) {
     return $CFG->wwwroot . '/mod/vpl/webservice.php?moodlewsrestformat=json'
            . '&wstoken=' . $token . '&id=' . $vpl->get_course_module()->id . '&wsfunction=';
 }
+
+function vpl_timestamp_to_midnight($timestamp) {
+    return $timestamp - ($timestamp + date('Z')) % 86400;
+}
\ No newline at end of file
diff --git a/similarity/diff.class.php b/similarity/diff.class.php
index 0b4849c8115693b9db865b7a029405175e99a81e..709df0850f57dc9fc2469a6040fecfb854ea8015 100644
--- a/similarity/diff.class.php
+++ b/similarity/diff.class.php
@@ -185,8 +185,7 @@ class vpl_diff {
                 }
                 if ($detaileddiff) {
                     $prize = self::diffline( $line, $lines2 [$j - 1] );
-                }
-                else {
+                } else {
                     $prize = $line === $lines2 [$j - 1] ? 1 : 0;
                 }
                 if ($matrix [$i - 1] [$j - 1] + $prize >= $max) {
@@ -393,4 +392,111 @@ class vpl_diff {
             print_error( 'type error' );
         }
     }
+
+    /**
+     * Computes diff between two lines.
+     * @param string $line1
+     * @param string $line2
+     * @return int The diff in number of chars.
+     */
+    static public function compute_linediff($line1, $line2) {
+        $n1 = strlen($line1);
+        $n2 = strlen($line2);
+        if ($n1 == 0 || $n2 == 0) {
+            return $n1 + $n2;
+        }
+        $queue = array_fill(0, $n1 + $n2 + 1, array());
+        $done = array_fill(0, $n1 + 1, array_fill(0, $n2 + 1, false));
+        $z = new stdClass();
+        $z->i1 = 0;
+        $z->i2 = 0;
+        $z->d = 0;
+        $queue[0][] = $z;
+        $priority = 0;
+
+        // A-star search of shortest diff.
+        while (true) {
+            while (count($queue[$priority]) == 0) {
+                $priority++;
+            }
+            $z = array_pop($queue[$priority]);
+            $i1 = $z->i1;
+            $i2 = $z->i2;
+            if ($done[$i1][$i2]) {
+                continue;
+            } else {
+                $done[$i1][$i2] = true;
+            }
+
+            // Identical substring: 0 distance.
+            while ($i1 < $n1 && $i2 < $n2 && $line1{$i1} == $line2{$i2}) {
+                $i1++;
+                $i2++;
+            }
+
+            if ($i1 == $n1 && $i2 == $n2) {
+                // Found shortest diff.
+                return $z->d;
+            }
+
+            // Character addition in line1.
+            if ($i1 < $n1) {
+                $z1 = new stdClass();
+                $z1->i1 = $i1 + 1;
+                $z1->i2 = $i2;
+                $z1->d = $z->d + 1;
+                $queue[$z1->d + abs(($n1 - $z1->i1) - ($n2 - $z1->i2))][] = $z1;
+            }
+
+            // Character addition in line2.
+            if ($i2 < $n2) {
+                $z2 = new stdClass();
+                $z2->i1 = $i1;
+                $z2->i2 = $i2 + 1;
+                $z2->d = $z->d + 1;
+                $queue[$z2->d + abs(($n1 - $z2->i1) - ($n2 - $z2->i2))][] = $z2;
+            }
+
+            // Character change.
+            if ($i1 < $n1 && $i2 < $n2) {
+                $z3 = new stdClass();
+                $z3->i1 = $i1 + 1;
+                $z3->i2 = $i2 + 1;
+                $z3->d = $z->d + 1;
+                $queue[$z3->d + abs(($n1 - $z3->i1) - ($n2 - $z3->i2))][] = $z3;
+            }
+        }
+    }
+
+    /**
+     * Computes diff between two files.
+     * @param string $filedata1
+     * @param string $filedata2
+     * @return int The diff in number of chars.
+     */
+    static public function compute_filediff($filedata1, $filedata2) {
+        if (strlen($filedata1) == 0 || strlen($filedata2) == 0) {
+            return strlen($filedata1) + strlen($filedata2);
+        }
+        $lines1 = explode("\n", $filedata1);
+        $lines2 = explode("\n", $filedata2);
+        $linesdiff = self::calculatediff($lines1, $lines2, false);
+        $totaldiff = 0;
+        foreach ($linesdiff as $diff) {
+            switch ($diff->type) {
+                case '=' :
+                    break;
+                case '<' :
+                    $totaldiff += strlen( $lines1[$diff->ln1 - 1] ) + 1;
+                    break;
+                case '>' :
+                    $totaldiff += strlen( $lines2[$diff->ln2 - 1] ) + 1;
+                    break;
+                default :
+                    $totaldiff += self::compute_linediff( $lines1[$diff->ln1 - 1], $lines2[$diff->ln2 - 1] );
+                    break;
+            }
+        }
+        return $totaldiff;
+    }
 }
diff --git a/styles.css b/styles.css
index ac3fbc14562018829072b6cd62cbe7b7edd874e9..d2fc4151a2580b506ef91f1226e4623851bb0d16 100644
--- a/styles.css
+++ b/styles.css
@@ -1,3 +1,18 @@
+/* ############################## */
+/* ##### Submissions charts ##### */
+/* ############################## */
+
+.path-mod-vpl.pagelayout-incourse .chart-area {
+    width: 50%;
+    height: 50%;
+    display: inline-block;
+}
+
+.path-mod-vpl .chart-area canvas {
+    width: 100%;
+    height: 100%;
+}
+
 /* ############################## */
 /* # Submissions list highlight # */
 /* ############################## */
diff --git a/views/activityworkinggraph.php b/views/activityworkinggraph.php
index aaae10d403608cd225c681df72abfcfcc674e120..f69eb80a3d7fd4bfdd8f9251132f7f3b3dc58d23 100644
--- a/views/activityworkinggraph.php
+++ b/views/activityworkinggraph.php
@@ -26,7 +26,7 @@
 require_once(dirname(__FILE__).'/../../../config.php');
 require_once(dirname(__FILE__).'/../locallib.php');
 require_once(dirname(__FILE__).'/../vpl.class.php');
-require_once(dirname(__FILE__).'/workinggraph.php');
+require_once(dirname(__FILE__).'/vpl_grapher.class.php');
 require_login();
 $id = required_param( 'id', PARAM_INT );
 $vpl = new mod_vpl( $id );
@@ -34,11 +34,10 @@ $vpl->prepare_page( 'views/activityworkinggraph.php', array (
         'id' => $id
 ) );
 
-$course = $vpl->get_course();
-$instance = $vpl->get_instance();
 $vpl->require_capability( VPL_GRADE_CAPABILITY );
 
-$vpl->print_header( get_string( 'timespent', VPL ) );
-$vpl->print_heading_with_help( 'timespent' );
-vpl_working_periods_graph($vpl, -1);
+$vpl->print_header_simple();
+$grapher = new vpl_grapher($vpl);
+$grapher->draw_working_periods_graph();
+$grapher->draw_daily_activity_graph();
 $vpl->print_footer_simple();
diff --git a/views/previoussubmissionslist.php b/views/previoussubmissionslist.php
index fef1aa5106a780796e17166e367c5a76ba441d70..c08d9d85b6695dff81f94d4ec6eb3df9773e9f17 100644
--- a/views/previoussubmissionslist.php
+++ b/views/previoussubmissionslist.php
@@ -27,29 +27,29 @@ require_once(dirname(__FILE__).'/../../../config.php');
 require_once(dirname(__FILE__).'/../locallib.php');
 require_once(dirname(__FILE__).'/../vpl.class.php');
 require_once(dirname(__FILE__).'/../vpl_submission.class.php');
+require_once(dirname(__FILE__).'/vpl_grapher.class.php');
 
 require_login();
 
 $id = required_param( 'id', PARAM_INT );
 $userid = required_param( 'userid', PARAM_INT );
-$detailed = abs( optional_param( 'detailed', 0, PARAM_INT ) ) % 2;
+$detailed = optional_param( 'detailed', 0, PARAM_INT );
 $vpl = new mod_vpl( $id );
 $vpl->prepare_page( 'views/previoussubmissionslist.php', array (
         'id' => $id,
         'userid' => $userid
 ) );
 
-$course = $vpl->get_course();
-if($USER->id != $userid /*|| !$vpl->get_instance()->allowshowprevious*/){ //Not owner
+global $USER, $OUTPUT, $DB;
+
+if ($USER->id != $userid /*|| !$vpl->get_instance()->allowshowprevious*/) {
     $vpl->require_capability(VPL_GRADE_CAPABILITY);
-    }
+}
 \mod_vpl\event\submission_previous_upload_viewed::log( array (
         'objectid' => $vpl->get_instance()->id,
         'context' => context_module::instance( $id ),
         'relateduserid' => $userid
 ) );
-$strdatesubmitted = get_string( 'datesubmitted', VPL );
-$strdescription = get_string( 'description', VPL );
 if ($detailed) {
     require_once(dirname(__FILE__).'/../views/sh_factory.class.php');
     vpl_sh_factory::include_js();
@@ -58,18 +58,27 @@ if ($detailed) {
 $vpl->print_header( get_string( 'previoussubmissionslist', VPL ) );
 $vpl->print_view_tabs( basename( __FILE__ ) );
 
+$grapher = new vpl_grapher($vpl, $userid);
+$grapher->draw_files_evolution_graph();
+$grapher->draw_working_periods_graph();
+$grapher->draw_files_evolution_graph(true);
+$grapher->draw_daily_activity_graph();
+
 $table = new html_table();
 $table->head = array (
         '#',
-        $strdatesubmitted,
-        $strdescription
+        get_string( 'datesubmitted', VPL ),
+        get_string( 'grade' ),
+        get_string( 'files' )
 );
 $table->align = array (
         'right',
         'left',
+        'left',
         'right'
 );
 $table->nowrap = array (
+        true,
         true,
         true,
         true
@@ -79,58 +88,56 @@ $submissions = array ();
 $nsub = count( $submissionslist );
 foreach ($submissionslist as $submission) {
     if ($detailed) {
-        $link = '#f' . $nsub;
+        $href = '#f' . $nsub;
+    } else {
+        $href = vpl_mod_href( 'forms/submissionview.php', 'id', $id, 'userid', $userid, 'submissionid', $submission->id );
+    }
+    $text = userdate($submission->datesubmitted);
+    $link = '<a href="' . $href . '"';
+    if ($submission->grader != 0) {
+        // Highlight submission as graded.
+        $gradingdetails = new stdClass();
+        $gradingdetails->date = userdate($submission->dategraded, get_string('strftimedate', 'langconfig'));
+        $grader = $DB->get_record('user', array( 'id' => $submission->grader ));
+        $gradingdetails->gradername = $vpl->fullname($grader, false);
+
+        $text .= ' (' . get_string('gradedonby', VPL, $gradingdetails) . ')';
+        $link .= ' style="color: red;"';
+    }
+    $link .= '>' . $text . '</a>';
+    if ($submission->dategraded > 0) {
+        $grade = $vpl->format_grade($submission->grade);
     } else {
-        $link = vpl_mod_href( 'forms/submissionview.php', 'id', $id, 'userid', $userid, 'submissionid', $submission->id );
+        $grade = get_string( 'nograde' );
     }
-    //$date = '<a href="' . $link . '">' . userdate( $submission->datesubmitted ) . '</a>';
-	if($submission->grader != 0) {
-		$date = '<a href="'.$link.'" style="color: rgb(255,0,0)">'.userdate($submission->datesubmitted).': Evaluated</a>';
-	}
-	else {
-		$date = '<a href="'.$link.'">'.userdate($submission->datesubmitted).'</a>';
-	}
-      $sub = new mod_vpl_submission( $vpl, $submission );
+    $sub = new mod_vpl_submission( $vpl, $submission );
     $submissions [] = $sub;
     $table->data [] = array (
             $nsub --,
-            $date,
+            $link,
+            $grade,
             s( $sub->get_detail() )
     );
 }
 
-echo '<div class="clearer"> </div>';
-echo '<div style="text-align: center">';
-echo '<img src="' . vpl_rel_url( 'submissionsgraph.php', 'id', $id, 'userid', $userid ) . '" alt="files size evolution" />';
-echo '</div>';
-echo '<div class="clearer"> </div>';
-echo '<div class="clearer"> </div>';
-echo '<div style="text-align: center">';
-echo '<img src="' . vpl_rel_url( 'workinggraph.php', 'id', $id, 'userid', $userid ) . '" alt="workingperiods" />';
-echo '</div>';
-echo '<div class="clearer"> </div>';
 echo html_writer::table( $table );
-echo '<div style="text-align:center">';
-$urlbase = $CFG->wwwroot . '/mod/vpl/views/previoussubmissionslist.php?id=' . $id . '&userid=' . $userid . '&detailed=';
+
+$urlbase = vpl_mod_href('views/previoussubmissionslist.php', 'id', $id, 'userid', $userid);
 $urls = array (
-        $urlbase . '0',
-        $urlbase . '1'
+        vpl_url_add_param($urlbase, 'detailed', 0),
+        vpl_url_add_param($urlbase, 'detailed', 1)
 );
 echo $OUTPUT->url_select( array (
         $urls [0] => get_string( 'detailedless' ),
         $urls [1] => get_string( 'detailedmore' )
-), $urls [$detailed] );
-echo '</div>';
+), $urls [$detailed], null );
 if ($detailed) {
     $nsub = count( $submissionslist );
-    foreach ($submissions as $index => $sub) {
+    foreach ($submissions as $sub) {
         echo '<hr><h2><a name="f' . $nsub . '"># ' . $nsub . '</a></h2>';
-
         $nsub --;
         $sub->print_submission();
     }
-}
-$vpl->print_footer();
-if ($detailed) {
     vpl_sh_factory::syntaxhighlight();
 }
+$vpl->print_footer();
diff --git a/views/submissionsgraph.php b/views/submissionsgraph.php
deleted file mode 100644
index 348e854743bbd2e257180badb1526819762340fc..0000000000000000000000000000000000000000
--- a/views/submissionsgraph.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
-//
-// VPL for Moodle 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.
-//
-// VPL for Moodle 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 VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Graph submissions statistics for a vpl instance and a user
- *
- * @package mod_vpl
- * @copyright 2012 onwards Juan Carlos Rodríguez-del-Pino
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-require_once(dirname(__FILE__).'/vpl_graph.class.php');
-
-function vpl_submissions_graph($vpl, $userid) {
-    global $DB;
-    $course = $vpl->get_course();
-    // No log.
-    $subsn = array ();
-    $series = array ();
-    $names = array ();
-    $submissionslist = $vpl->user_submissions( $userid );
-    if (count( $submissionslist ) > 0) {
-        $submissionslist = array_reverse( $submissionslist );
-        // Create submissions object.
-        $subs = array ();
-        foreach ($submissionslist as $submission) {
-            $subs [] = new mod_vpl_submission( $vpl, $submission );
-        }
-        foreach ($subs as $sub) {
-            $filesarray = $sub->get_submitted_fgm()->getfilelist();
-            foreach ($filesarray as $name) {
-                if (! in_array( $name, $names, true )) {
-                    $names [] = $name;
-                    $series [$name] = array ();
-                }
-            }
-        }
-        // Initial value.
-        $subshowl = ( int ) (count( $subs ) / 20);
-        if ($subshowl < 1) {
-            $subshow = 1;
-        } else {
-            $subshow = 5;
-            while ( true ) {
-                if ($subshow >= $subshowl) {
-                    break;
-                }
-                $subshow *= 2;
-                if ($subshow >= $subshowl) {
-                    break;
-                }
-                $subshow = ( int ) (2.5 * $subshow);
-                if ($subshow >= $subshowl) {
-                    break;
-                }
-                $subshow *= 2;
-                if ($subshow >= $subshowl) {
-                    break;
-                }
-            }
-        }
-        $nsub = 1;
-        foreach ($subs as $sub) {
-            $subsn [] = $nsub % $subshow == 0 ? $nsub : '';
-            $filesarray = $sub->get_submitted_files();
-            $files = array ();
-            foreach ($filesarray as $name => $data) {
-                $size = strlen( $data );
-                $files [$name] = $size;
-            }
-            foreach ($names as $name) {
-                if (isset( $files [$name] )) {
-                    $series [$name] [$nsub - 1] = $files [$name];
-                } else {
-                    $series [$name] [$nsub - 1] = null;
-                }
-            }
-            $nsub ++;
-        }
-    }
-    $user = $DB->get_record( 'user', array (
-            'id' => $userid
-    ) );
-    vpl_graph::draw( $vpl->get_printable_name() . ' - ' . $vpl->fullname( $user, false )
-                   , get_string( 'submissions', VPL ) , get_string( "sizeb" ), $subsn, $series, $names );
-}
\ No newline at end of file
diff --git a/views/vpl_graph.class.php b/views/vpl_graph.class.php
deleted file mode 100644
index c86a3ef56bb72ebd3171e762ad832d9519565cc0..0000000000000000000000000000000000000000
--- a/views/vpl_graph.class.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
-//
-// VPL for Moodle 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.
-//
-// VPL for Moodle 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 VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Graph submissions statistics for a vpl instance and a user
- *
- * @package mod_vpl
- * @copyright 2012 onwards Juan Carlos Rodríguez-del-Pino
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->libdir . '/graphlib.php');
-
-class vpl_graph {
-    /**
-     * Draw a graph image. Staked area
-     *
-     * @param $title string title of graph
-     * @param $xlabel string x label
-     * @param $ylabel string y label
-     * @param $legends array of strings, values are the names of every serie
-     * @param $xdata array x labels
-     * @param $ydata array of array of numbers first array is indexed by legend.
-     * @return void
-     */
-    static public function draw($title, $xlabel, $ylabel, $xdata, $ydata, $legends = false, $typebar = false) {
-        global $OUTPUT;
-        $chart = new \core\chart_bar();
-        $chart->set_stacked(true);
-        $chart->set_title($title);
-        $chart->set_labels($xdata);
-        $chart->get_xaxis(0, true)->set_label($xlabel);
-        $chart->get_yaxis(0, true)->set_label($ylabel);
-        $chart->get_xaxis(0, true)->set_labels($xdata);
-        if ( $legends == false) {
-            $serie = new \core\chart_series($ylabel, $ydata);
-            $chart->add_series($serie);
-        } else {
-            $chart->set_stacked(true);
-            foreach ($legends as $legen) {
-                $serie = new \core\chart_series($legen, $ydata[$legen]);
-                $serie->set_smooth(true);
-                $serie->set_type($serie::TYPE_LINE);
-                $chart->add_series($serie);
-            }
-        }
-        echo $OUTPUT->render($chart);
-    }
-}
diff --git a/views/vpl_grapher.class.php b/views/vpl_grapher.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..4769428c36c1ba329eb6afdf08a8634950252f07
--- /dev/null
+++ b/views/vpl_grapher.class.php
@@ -0,0 +1,339 @@
+<?php
+// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
+//
+// VPL for Moodle 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.
+//
+// VPL for Moodle 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 VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Graph submissions statistics for a vpl instance and a user
+ *
+ * @package mod_vpl
+ * @copyright 2012 onwards Juan Carlos Rodríguez-del-Pino
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once(dirname(__FILE__).'/../locallib.php');
+require_once(dirname(__FILE__).'/../vpl.class.php');
+require_once(dirname(__FILE__).'/../vpl_submission.class.php');
+require_once(dirname(__FILE__).'/../similarity/diff.class.php');
+
+class vpl_grapher {
+
+    protected $vpl;
+    protected $submissions;
+    protected $userid;
+    protected $username;
+
+    public function __construct(&$vpl, $userid = null) {
+        $this->vpl = $vpl;
+        $this->userid = $userid;
+        if ($userid !== null) {
+            global $DB;
+            $user = $DB->get_record( 'user', array (
+                    'id' => $userid
+            ));
+            $this->username = $vpl->fullname($user, false);
+            $usersubs = $vpl->user_submissions( $userid );
+            $this->submissions = $usersubs;
+            $this->userssubmissions = array();
+            $this->userssubmissions[] = $usersubs;
+        } else {
+            $this->submissions = array();
+            $this->userssubmissions = array();
+            $cm = $vpl->get_course_module();
+            $currentgroup = groups_get_activity_group( $cm );
+            if (! $currentgroup) {
+                $currentgroup = '';
+            }
+            $list = $vpl->get_students( $currentgroup );
+            foreach ($list as $userinfo) {
+                if ($vpl->is_group_activity() && $userinfo->id != $vpl->get_group_leaderid( $userinfo->id )) {
+                    continue;
+                }
+                $usersubs = $vpl->user_submissions( $userinfo->id );
+                $this->submissions = array_merge($this->submissions, $usersubs);
+                $this->userssubmissions[] = $usersubs;
+            }
+        }
+    }
+
+    /**
+     * Draw a graph in page.
+     *
+     * @param $title string title of graph
+     * @param $xlabel string x label
+     * @param $ylabel string y label
+     * @param $xdata array x labels
+     * @param $ydata array of array of numbers first array is indexed by legend.
+     * @param $seriesnames array of strings, values are the names of every series.
+     *      If provided, the chart will render as stacked line series. Otherwise, it will render as a bar chart.
+     */
+    static protected function draw($title, $xlabel, $ylabel, $xdata, $ydata, $seriesnames = null) {
+        global $OUTPUT, $CFG;
+        require_once($CFG->libdir . '/graphlib.php');
+        $chart = new \core\chart_bar();
+        $chart->set_title($title);
+        $chart->set_labels($xdata);
+        $chart->get_xaxis(0, true)->set_label($xlabel);
+        $chart->get_yaxis(0, true)->set_label($ylabel);
+        $chart->get_xaxis(0, true)->set_labels($xdata);
+        if ( $seriesnames === null) {
+            $serie = new \core\chart_series($ylabel, $ydata);
+            $chart->add_series($serie);
+        } else {
+            $chart->set_stacked(false);
+            foreach ($seriesnames as $seriesname) {
+                $serie = new \core\chart_series($seriesname, $ydata[$seriesname]);
+                $serie->set_smooth(false);
+                $serie->set_type($serie::TYPE_LINE);
+                $chart->add_series($serie);
+            }
+        }
+        echo $OUTPUT->render($chart);
+    }
+
+    /**
+     * Computes a value in {1,5,10,25,50,100,250,500,...} that will render fine as x-axis legend.
+     * @param $totalvalues int The number of values on x-axis
+     * @param $legendsnumber int The number of legends to display on x-axis
+     */
+    static protected function compute_xaxis_legend_interval($totalvalues, $legendsnumber) {
+        $x = ( int ) ($totalvalues / $legendsnumber); // First estimation.
+        if ($x == 0) {
+            return 1;
+        }
+        $interval = 10 ** strlen($x);
+        if ($interval / 2 > $x) {
+            $interval /= 2;
+            if ($interval / 2 > $x) {
+                $interval /= 2;
+            }
+        }
+        return max( $interval, 5 );
+    }
+
+    /**
+     * Draw a graph showing submitted files evolution.
+     * @param boolean $diff Whether the graph should show the diff with required files, or the total size of the files.
+     */
+    public function draw_files_evolution_graph($diff = false) {
+        if (count( $this->submissions ) == 0 || $this->userid === null) {
+            return;
+        }
+        $submissionslist = array_reverse( $this->submissions );
+
+        $interval = self::compute_xaxis_legend_interval(count( $submissionslist ), 20);
+
+        $i = 1;
+        $subsn = array();
+        $series = array();
+        $names = array();
+        $totalseries = array();
+        if ($diff) {
+            $reqfiles = $this->vpl->get_fgm('required')->getAllFiles();
+        }
+        foreach ($submissionslist as $subinstance) {
+            $submission = new mod_vpl_submission( $this->vpl, $subinstance );
+            $files = $submission->get_submitted_files();
+            $total = 0;
+            foreach ($files as $name => $data) {
+                if (!isset($series[$name])) {
+                    $names[] = $name;
+                    $series[$name] = array_fill(0, $i - 1, null);
+                }
+                if ($diff && isset($reqfiles[$name])) {
+                    $value = vpl_diff::compute_filediff($reqfiles[$name], $data);
+                } else {
+                    $value = strlen( $data );
+                }
+                $series[$name][] = $value;
+                $total += $value;
+            }
+            foreach ($series as &$serie) {
+                if (count($serie) < $i) {
+                    $serie[] = null;
+                }
+            }
+            $totalseries[] = $total;
+            $subsn[] = $i % $interval == 0 ? $i : '';
+            $i++;
+        }
+        if ($diff && count($names) > 1) {
+            $names[] = get_string('total');
+            $series[get_string('total')] = $totalseries;
+        }
+        $title = $this->username . ' - ';
+        if ($diff) {
+            $title .= get_string( 'filesdiffevolution', VPL );
+        } else {
+            $title .= get_string( 'filessizeevolution', VPL );
+        }
+        self::draw( $title, get_string( 'submissions', VPL ) , get_string( "sizeb" ), $subsn, $series, $names );
+    }
+
+    static protected function new_working_period($workduration, &$firstwork, $intervals) {
+        if ($intervals > 0) { // First work as average.
+            $firstwork = ( float ) $workduration / $intervals;
+        }
+        // Else use the last $firstwork.
+        return ($workduration + $firstwork);
+    }
+
+    protected function get_working_periods() {
+        $workperiods = array ();
+        foreach ($this->userssubmissions as $usersubs) {
+            if (count( $usersubs ) == 0) {
+                continue;
+            }
+            $usersubs = array_reverse( $usersubs );
+            $userworkperiods = array ();
+            $lastsavetime = 0;
+            $resttime = 20 * 60; // Rest period before next work 20 minutes.
+            $firstwork = 10 * 60; // Work before first save 10 minutes.
+            $intervals = - 1;
+            $workstart = 0;
+            foreach ($usersubs as $submission) {
+                // Start new work period.
+                if ($submission->datesubmitted - $lastsavetime >= $resttime) {
+                    if ($workstart > 0) { // Is not the first submission.
+                        $userworkperiods[] = self::new_working_period($lastsavetime - $workstart, $firstwork, $intervals);
+                    }
+                    $workstart = $submission->datesubmitted;
+                    $intervals = 0;
+                } else { // Count interval.
+                    $intervals ++;
+                }
+                $lastsavetime = $submission->datesubmitted;
+            }
+            $userworkperiods[] = self::new_working_period($lastsavetime - $workstart, $firstwork, $intervals);
+            $workperiods[] = $userworkperiods;
+        }
+        return $workperiods;
+    }
+
+    public function draw_working_periods_graph() {
+        if (count( $this->submissions ) == 0) {
+            return;
+        }
+        if ($this->userid === null) {
+            $alldata = self::get_working_periods();
+            // For every student, total time, number of period.
+            $totaltime = 0;
+            $maxstudenttime = 0;
+            $maxperiodtime = 0;
+            $totalperiods = 0;
+            $times = array ();
+            foreach ($alldata as $workingperiods) {
+                $totalperiods += count( $workingperiods );
+                $time = 0;
+                foreach ($workingperiods as $period) {
+                    $time += $period / 3600.0;
+                    $maxperiodtime = max( $maxperiodtime, $period / 3600.0 );
+                }
+                $totaltime += $time;
+                $maxstudenttime = max( $maxstudenttime, $time );
+                $times [] = $time;
+            }
+            if ($maxstudenttime <= 3) {
+                $timeslice = 0.25;
+                $xformat = "%3.2f-%3.2f";
+            } else if ($maxstudenttime <= 6) {
+                $timeslice = 0.50;
+                $xformat = "%3.1f-%3.1f";
+            } else {
+                $timeslice = 1;
+                $xformat = "%3.0f-%3.0f";
+            }
+            $ydata = array ();
+            $xdata = array ();
+            for ($slice = 0; $slice <= $maxstudenttime; $slice += $timeslice) {
+                $ydata [] = 0;
+                $xdata [] = sprintf( $xformat, $slice, ($slice + $timeslice) );
+            }
+            foreach ($times as $time) {
+                $ydata [( int ) ($time / $timeslice)] ++;
+            }
+            $title = $this->vpl->get_printable_name();
+            $n = count( $times );
+            $straveragetime = get_string( 'averagetime', VPL, sprintf( '%3.1f', (( float ) $totaltime / $n) ) );
+            $straverageperiods = get_string( 'averageperiods', VPL, sprintf( '%3.1f', (( float ) $totalperiods / $n) ) );
+            $strvmaximumperiod = get_string( 'maximumperiod', VPL, sprintf( '%3.1f', (( float ) $maxperiodtime) ) );
+            $xtitle = sprintf( '%s - %s - %s - %s', get_string( 'hours' ),
+                    $straveragetime, $straverageperiods, $strvmaximumperiod );
+            $ytitle = get_string( 'defaultcoursestudents' );
+            self::draw( $title, $xtitle, $ytitle, $xdata, $ydata );
+        } else {
+            $workingperiods = self::get_working_periods()[0];
+            $xdata = array ();
+            $totaltime = 0.0;
+            $i = 1;
+            foreach ($workingperiods as &$period) {
+                $xdata[] = '#' . ($i++);
+                $totaltime += $period;
+                $period = round($period / 60.0, 2);
+            }
+            $title = $this->username . ' - ' . format_time( $totaltime );
+            self::draw( $title, get_string( 'workingperiods', VPL ), get_string( 'minutes' ), $xdata, $workingperiods );
+        }
+    }
+
+    public function draw_daily_activity_graph() {
+        if (count( $this->submissions ) == 0) {
+            return;
+        }
+
+        // Beginning of time span is either module start date, either first submission date.
+        if ($this->vpl->get_instance()->startdate > 0) {
+            $start = $this->vpl->get_instance()->startdate;
+        } else {
+            $start = time();
+            foreach ($this->submissions as $subinstance) {
+                $start = min($start, $subinstance->datesubmitted);
+            }
+        }
+        $start = vpl_timestamp_to_midnight($start);
+
+        // End of time span is either module due date, either now.
+        if ($this->vpl->get_instance()->duedate > 0) {
+            $end = $this->vpl->get_instance()->duedate;
+        } else {
+            $end = time();
+        }
+        $end = vpl_timestamp_to_midnight($end);
+
+        // Compute per-day activity (ie. number of submissions).
+        $days = array();
+        $dailyactivity = array();
+        for ($day = $start; $day <= $end; $day += 86400) {
+            $days[] = userdate($day, get_string('strftimedate', 'langconfig'));
+            $dailyactivity[] = 0;
+        }
+
+        foreach ($this->submissions as $subinstance) {
+            $daysubmitted = vpl_timestamp_to_midnight($subinstance->datesubmitted);
+            $dailyactivity[($daysubmitted - $start) / 86400] ++;
+        }
+
+        // Draw the graph.
+        if ($this->userid === null) {
+            $title = $this->vpl->get_printable_name();
+        } else {
+            $title = $this->username;
+        }
+        $title .= ' - ' . get_string( 'nsubmissions', VPL, count($this->submissions) );
+        self::draw( $title, get_string( 'day' ), get_string( 'submissions', VPL ), $days, $dailyactivity );
+    }
+}
diff --git a/views/workinggraph.php b/views/workinggraph.php
deleted file mode 100644
index 91e040bc079add8939dc6b28719028eac0b83a21..0000000000000000000000000000000000000000
--- a/views/workinggraph.php
+++ /dev/null
@@ -1,161 +0,0 @@
-<?php
-// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
-//
-// VPL for Moodle 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.
-//
-// VPL for Moodle 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 VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.
- 
-/**
- * Graph working time for a vpl instance and/or a user
- *
- * @package        mod_vpl
- * @copyright    2012 Juan Carlos Rodríguez-del-Pino
- * @license        http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @author        Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
- */
- 
-require_once(dirname( __FILE__ ) . '/../../../config.php');
-require_once(dirname( __FILE__ ) . '/vpl_graph.class.php');
-require_once(dirname( __FILE__ ) . '/../locallib.php');
-require_once(dirname( __FILE__ ) . '/../vpl.class.php');
-require_once(dirname( __FILE__ ) . '/../vpl_submission.class.php');
-
-function vpl_get_working_periods($vpl, $userid) {
-    $submissionslist = $vpl->user_submissions( $userid );
-    if (count( $submissionslist ) == 0) {
-        return array ();
-    }
-    $submissionslist = array_reverse( $submissionslist );
-    $workperiods = array ();
-    if ($submissionslist) {
-        $lastsavetime = 0;
-        $resttime = 20 * 60; // Rest period before next work 20 minutes.
-        $firstwork = 10 * 59; // Work before first save 10 minutes.
-        $intervals = - 1;
-        $workstart = 0;
-        foreach ($submissionslist as $submission) {
-            /* Start new work period */
-            if ($submission->datesubmitted - $lastsavetime >= $resttime) {
-                if ($workstart > 0) { // Is not the first submission.
-                    if ($intervals > 0) { // First work as average.
-                        $firstwork = ( float ) ($lastsavetime - $workstart) / $intervals;
-                    }
-                    // Else use the last $firstwork.
-                    $workperiods [] = ($lastsavetime - $workstart + $firstwork) / (3600.0);
-                }
-                $workstart = $submission->datesubmitted;
-                $intervals = 0;
-            } else { // Count interval.
-                $intervals ++;
-            }
-            $lastsavetime = $submission->datesubmitted;
-        }
-        if ($intervals > 0) { // First work as average.
-            $firstwork = ( float ) ($lastsavetime - $workstart) / $intervals;
-        } // Else use the last $firstwork.
-        $workperiods [] = ($lastsavetime - $workstart + $firstwork) / (3600.0);
-    }
-    return $workperiods;
-}
- 
-require_login();
- 
-$id = required_param( 'id', PARAM_INT );
-$userid = optional_param( 'userid', - 1, PARAM_INT );
-$type = optional_param( 'type', 0, PARAM_INT );
-$vpl = new mod_vpl( $id );
-$course = $vpl->get_course();
-if($USER->id != $userid /*|| !$vpl->get_instance()->allowshowprevious*/){ //Not owner or not allow
-    $vpl->require_capability(VPL_GRADE_CAPABILITY);
-}
-// No log.
-if ($userid < 0) {
-    $cm = $vpl->get_course_module();
-    $currentgroup = groups_get_activity_group( $cm );
-    if (! $currentgroup) {
-        $currentgroup = '';
-    }
-    $list = $vpl->get_students( $currentgroup );
-    $submissions = $vpl->all_last_user_submission();
-    // Get all information.
-    $alldata = array ();
-    foreach ($list as $userinfo) {
-        if ($vpl->is_group_activity() && $userinfo->id != $vpl->get_group_leaderid( $userinfo->id )) {
-            continue;
-        }
-        $workingperiods = vpl_get_working_periods( $vpl, $userinfo->id );
-        if (count( $workingperiods ) > 0) {
-            $alldata [] = $workingperiods;
-        }
-    }
-    session_write_close();
-    // For every student, total time, number of period.
-    $totaltime = 0;
-    $maxstudenttime = 0;
-    $maxperiodtime = 0;
-    $totalperiods = 0;
-    $times = array ();
-    foreach ($alldata as $workingperiods) {
-        $totalperiods += count( $workingperiods );
-        $time = 0;
-        foreach ($workingperiods as $period) {
-            $time += $period;
-            $maxperiodtime = max( $maxperiodtime, $period );
-        }
-        $totaltime += $time;
-        $maxstudenttime = max( $maxstudenttime, $time );
-        $times [] = $time;
-          }
-    if ($maxstudenttime <= 3) {
-        $timeslice = 0.25;
-        $xformat = "%3.2f-%3.2f";
-    } else if ($maxstudenttime <= 6) {
-        $timeslice = 0.50;
-        $xformat = "%3.1f-%3.1f";
-    } else {
-        $timeslice = 1;
-        $xformat = "%3.0f-%3.0f";
-    }
-    $ydata = array ();
-    $xdata = array ();
-    for ($slice = 0; $slice <= $maxstudenttime; $slice += $timeslice) {
-        $ydata [] = 0;
-        $xdata [] = sprintf( $xformat, $slice, ($slice + $timeslice) );
-    }
-    foreach ($times as $time) {
-        $ydata [( int ) ($time / $timeslice)] ++;
-    }
-    $title = $vpl->get_printable_name();
-    $n = count( $times );
-    $straveragetime = get_string( 'averagetime', VPL, sprintf( '%3.1f', (( float ) $totaltime / $n) ) );
-    $straverageperiods = get_string( 'averageperiods', VPL, sprintf( '%3.1f', (( float ) $totalperiods / $n) ) );
-    $strvmaximumperiod = get_string( 'maximumperiod', VPL, sprintf( '%3.1f', (( float ) $maxperiodtime) ) );
-    $xtitle = sprintf( '%s - %s - %s - %s', get_string( 'hours' ), $straveragetime, $straverageperiods, $strvmaximumperiod );
-    $ytitle = get_string( 'defaultcoursestudents' );
-    vpl_graph::draw( $title, $xtitle, $ytitle, $xdata, $ydata, null, true );
-} else {
-    $ydata = vpl_get_working_periods( $vpl, $userid );
-    session_write_close();
-    $xdata = array ();
-    $hours = 0.0;
-    for ($i = 0; $i < count( $ydata ); $i ++) {
-        $xdata [] = $i + 1;
-        $hours += $ydata [$i];
-    }
-    $user = $DB->get_record( 'user', array (
-            'id' => $userid
-    ) );
-    $title = sprintf( "%s - %s", $vpl->fullname( $user, false ), get_string( 'numhours', '', sprintf( '%3.2f', $hours ) ) );
-    $titlex = get_string( 'workingperiods', VPL ) . ' - ' . $vpl->get_printable_name();
-    vpl_graph::draw( $title, $titlex, get_string( 'hours' ), $xdata, $ydata, null, true );
-}
- 
diff --git a/vpl.class.php b/vpl.class.php
index 17e8b3f0bceaccac2335d6e538f34831d8d55bbd..ad0bc342daa018e215047d266afe7086f5f83502 100644
--- a/vpl.class.php
+++ b/vpl.class.php
@@ -1306,6 +1306,15 @@ class mod_vpl {
         return $this->instance->grade;
     }
 
+    /**
+     * Format given grade as grade/maxgrade
+     * @param float $grade
+     * @return string Printable grade
+     */
+    public function format_grade($grade) {
+        return format_float($grade, 2, true, false) . ' / ' . format_float($this->get_grade(), 2, true, false);
+    }
+
     /**
      * print end of page
      */