diff --git a/admin/settings/analytics.php b/admin/settings/analytics.php
index 5f43a52ae17..dfbb1d69ba0 100644
--- a/admin/settings/analytics.php
+++ b/admin/settings/analytics.php
@@ -75,7 +75,7 @@ if ($hassiteconfig) {
$defaultreader, $options));
// Enable/disable time splitting methods.
- $alltimesplittings = \core_analytics\manager::get_all_time_splittings();
+ $alltimesplittings = \core_analytics\manager::get_time_splitting_methods_for_evaluation(true);
$timesplittingoptions = array();
$timesplittingdefaults = array('\core\analytics\time_splitting\quarters_accum',
diff --git a/admin/tool/analytics/amd/build/model.min.js b/admin/tool/analytics/amd/build/model.min.js
index 9e958dbd395..fd1374c5987 100644
--- a/admin/tool/analytics/amd/build/model.min.js
+++ b/admin/tool/analytics/amd/build/model.min.js
@@ -1 +1 @@
-define(["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){var h={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},"delete":{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}},i=function(b){return a(b.closest("tr")[0]).find("span.target-name").text()};return{confirmAction:function(g,j){a('[data-action-id="'+g+'"]').on("click",function(g){g.preventDefault();var k=a(g.currentTarget);if("undefined"==typeof h[j])return void c.error('Action "'+j+'" is not allowed.');var l=[h[j].title,h[j].body];l[1].param=i(k);var m=b.get_strings(l),n=e.create({type:e.types.SAVE_CANCEL});a.when(m,n).then(function(a,b){return b.setTitle(a[0]),b.setBody(a[1]),b.setSaveButtonText(a[0]),b.getRoot().on(f.save,function(){window.location.href=k.attr("href")}),b.show(),b}).fail(d.exception)})},selectEvaluationMode:function(c,h){a('[data-action-id="'+c+'"]').on("click",function(c){c.preventDefault();var i=a(c.currentTarget);if(!h)return void(window.location.href=i.attr("href"));var j=b.get_strings([{key:"evaluatemodel",component:"tool_analytics"},{key:"evaluationmode",component:"tool_analytics"}]),k=e.create({type:e.types.SAVE_CANCEL}),l=g.render("tool_analytics/evaluation_mode_selection",{});a.when(j,k).then(function(b,c){return c.getRoot().on(f.hidden,c.destroy.bind(c)),c.setTitle(b[1]),c.setSaveButtonText(b[0]),c.setBody(l),c.getRoot().on(f.save,function(){var b=a("input[name='evaluationmode']:checked").val();"trainedmodel"==b&&i.attr("href",i.attr("href")+"&mode=trainedmodel"),window.location.href=i.attr("href")}),c.show(),c}).fail(d.exception)})},selectExportOptions:function(c,h){a('[data-action-id="'+c+'"]').on("click",function(c){c.preventDefault();var i=a(c.currentTarget);if(!h)return i.attr("href",i.attr("href")+"&action=exportmodel&includeweights=0"),void(window.location.href=i.attr("href"));var j=b.get_strings([{key:"export",component:"tool_analytics"}]),k=e.create({type:e.types.SAVE_CANCEL}),l=g.render("tool_analytics/export_options",{});a.when(j,k).then(function(b,c){return c.getRoot().on(f.hidden,c.destroy.bind(c)),c.setTitle(b[0]),c.setSaveButtonText(b[0]),c.setBody(l),c.getRoot().on(f.save,function(){var b=a("input[name='exportoption']:checked").val();"exportdata"==b?i.attr("href",i.attr("href")+"&action=exportdata"):(i.attr("href",i.attr("href")+"&action=exportmodel"),a("#id-includeweights").is(":checked")?i.attr("href",i.attr("href")+"&includeweights=1"):i.attr("href",i.attr("href")+"&includeweights=0")),window.location.href=i.attr("href")}),c.show(),c}).fail(d.exception)})}}});
\ No newline at end of file
+define(["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){var h={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},"delete":{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}},i=function(b){return a(b.closest("tr")[0]).find("span.target-name").text()};return{confirmAction:function(g,j){a('[data-action-id="'+g+'"]').on("click",function(g){g.preventDefault();var k=a(g.currentTarget);if("undefined"==typeof h[j])return void c.error('Action "'+j+'" is not allowed.');var l=[h[j].title,h[j].body];l[1].param=i(k);var m=b.get_strings(l),n=e.create({type:e.types.SAVE_CANCEL});a.when(m,n).then(function(a,b){return b.setTitle(a[0]),b.setBody(a[1]),b.setSaveButtonText(a[0]),b.getRoot().on(f.save,function(){window.location.href=k.attr("href")}),b.show(),b}).fail(d.exception)})},selectEvaluationOptions:function(c,h,i){a('[data-action-id="'+c+'"]').on("click",function(c){c.preventDefault();var j=a(c.currentTarget),k=b.get_strings([{key:"evaluatemodel",component:"tool_analytics"},{key:"evaluate",component:"tool_analytics"}]),l=e.create({type:e.types.SAVE_CANCEL}),m=g.render("tool_analytics/evaluation_options",{trainedexternally:h,timesplittingmethods:i});a.when(k,l).then(function(b,c){return c.getRoot().on(f.hidden,c.destroy.bind(c)),c.setTitle(b[0]),c.setSaveButtonText(b[1]),c.setBody(m),c.getRoot().on(f.save,function(){var b=a("input[name='evaluationmode']:checked").val();"trainedmodel"==b&&j.attr("href",j.attr("href")+"&mode=trainedmodel");var c=a("#id-evaluation-timesplitting").val();j.attr("href",j.attr("href")+"×plitting="+c),window.location.href=j.attr("href")}),c.show(),c}).fail(d.exception)})},selectExportOptions:function(c,h){a('[data-action-id="'+c+'"]').on("click",function(c){c.preventDefault();var i=a(c.currentTarget);if(!h)return i.attr("href",i.attr("href")+"&action=exportmodel&includeweights=0"),void(window.location.href=i.attr("href"));var j=b.get_strings([{key:"export",component:"tool_analytics"}]),k=e.create({type:e.types.SAVE_CANCEL}),l=g.render("tool_analytics/export_options",{});a.when(j,k).then(function(b,c){return c.getRoot().on(f.hidden,c.destroy.bind(c)),c.setTitle(b[0]),c.setSaveButtonText(b[0]),c.setBody(l),c.getRoot().on(f.save,function(){var b=a("input[name='exportoption']:checked").val();"exportdata"==b?i.attr("href",i.attr("href")+"&action=exportdata"):(i.attr("href",i.attr("href")+"&action=exportmodel"),a("#id-includeweights").is(":checked")?i.attr("href",i.attr("href")+"&includeweights=1"):i.attr("href",i.attr("href")+"&includeweights=0")),window.location.href=i.attr("href")}),c.show(),c}).fail(d.exception)})}}});
\ No newline at end of file
diff --git a/admin/tool/analytics/amd/src/model.js b/admin/tool/analytics/amd/src/model.js
index 8d35e8648b7..7a33345350d 100644
--- a/admin/tool/analytics/amd/src/model.js
+++ b/admin/tool/analytics/amd/src/model.js
@@ -101,50 +101,53 @@ define(['jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_facto
},
/**
- * Displays a select-evaluation-mode choice.
+ * Displays evaluation mode and time-splitting method choices.
*
* @param {String} actionId
* @param {Boolean} trainedOnlyExternally
*/
- selectEvaluationMode: function(actionId, trainedOnlyExternally) {
+ selectEvaluationOptions: function(actionId, trainedOnlyExternally, timeSplittingMethods) {
$('[data-action-id="' + actionId + '"]').on('click', function(ev) {
ev.preventDefault();
var a = $(ev.currentTarget);
- if (!trainedOnlyExternally) {
- // We can not evaluate trained models if the model was trained using data from this site.
- // Default to evaluate the model configuration if that is the case.
- window.location.href = a.attr('href');
- return;
- }
-
var stringsPromise = Str.get_strings([
{
key: 'evaluatemodel',
component: 'tool_analytics'
}, {
- key: 'evaluationmode',
+ key: 'evaluate',
component: 'tool_analytics'
}
]);
var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
- var bodyPromise = Templates.render('tool_analytics/evaluation_mode_selection', {});
+ var bodyPromise = Templates.render('tool_analytics/evaluation_options', {
+ trainedexternally: trainedOnlyExternally,
+ timesplittingmethods: timeSplittingMethods
+ });
$.when(stringsPromise, modalPromise).then(function(strings, modal) {
modal.getRoot().on(ModalEvents.hidden, modal.destroy.bind(modal));
- modal.setTitle(strings[1]);
- modal.setSaveButtonText(strings[0]);
+ modal.setTitle(strings[0]);
+ modal.setSaveButtonText(strings[1]);
modal.setBody(bodyPromise);
modal.getRoot().on(ModalEvents.save, function() {
+
+ // Evaluation mode.
var evaluationMode = $("input[name='evaluationmode']:checked").val();
if (evaluationMode == 'trainedmodel') {
a.attr('href', a.attr('href') + '&mode=trainedmodel');
}
+
+ // Selected time-splitting id.
+ var timeSplittingMethod = $("#id-evaluation-timesplitting").val();
+ a.attr('href', a.attr('href') + '×plitting=' + timeSplittingMethod);
+
window.location.href = a.attr('href');
return;
});
diff --git a/admin/tool/analytics/classes/output/helper.php b/admin/tool/analytics/classes/output/helper.php
index 861d6794f83..e00ee0b88d6 100644
--- a/admin/tool/analytics/classes/output/helper.php
+++ b/admin/tool/analytics/classes/output/helper.php
@@ -45,7 +45,7 @@ class helper {
// Form field is PARAM_ALPHANUMEXT and we are sending fully qualified class names
// as option names, but replacing the backslash for a string that is really unlikely
// to ever be part of a class name.
- return str_replace('\\', '2015102400ouuu', $class);
+ return str_replace('\\', '__', $class);
}
/**
@@ -56,7 +56,7 @@ class helper {
*/
public static function option_to_class($option) {
// Really unlikely but yeah, I'm a bad booyyy.
- return str_replace('2015102400ouuu', '\\', $option);
+ return str_replace('__', '\\', $option);
}
/**
diff --git a/admin/tool/analytics/classes/output/models_list.php b/admin/tool/analytics/classes/output/models_list.php
index 5152b6d273f..96bfc829bc4 100644
--- a/admin/tool/analytics/classes/output/models_list.php
+++ b/admin/tool/analytics/classes/output/models_list.php
@@ -71,6 +71,17 @@ class models_list implements \renderable, \templatable {
$onlycli = 1;
}
+ // Evaluation options.
+ $timesplittingmethods = [
+ ['id' => 'all', 'text' => get_string('alltimesplittingmethods', 'tool_analytics')],
+ ];
+ foreach (\core_analytics\manager::get_time_splitting_methods_for_evaluation(true) as $timesplitting) {
+ $timesplittingmethods[] = [
+ 'id' => \tool_analytics\output\helper::class_to_option($timesplitting->get_id()),
+ 'text' => $timesplitting->get_name()->out(),
+ ];
+ }
+
$data->models = array();
foreach ($this->models as $model) {
$modeldata = $model->export();
@@ -192,7 +203,15 @@ class models_list implements \renderable, \templatable {
$trainedonlyexternally = !$model->trained_locally() && $model->is_trained();
$actionid = 'evaluate-' . $model->get_id();
- $PAGE->requires->js_call_amd('tool_analytics/model', 'selectEvaluationMode', [$actionid, $trainedonlyexternally]);
+
+ // Include the current time-splitting method as the default selection method the model already have one.
+ if ($model->get_model_obj()->timesplitting) {
+ $currenttimesplitting = ['id' => 'current', 'text' => get_string('currenttimesplitting', 'tool_analytics')];
+ array_unshift($timesplittingmethods, $currenttimesplitting);
+ }
+
+ $evaluateparams = [$actionid, $trainedonlyexternally, $timesplittingmethods];
+ $PAGE->requires->js_call_amd('tool_analytics/model', 'selectEvaluationOptions', $evaluateparams);
$urlparams['action'] = 'evaluate';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')),
diff --git a/admin/tool/analytics/lang/en/tool_analytics.php b/admin/tool/analytics/lang/en/tool_analytics.php
index b3a8ba42cf1..6f4897864b4 100644
--- a/admin/tool/analytics/lang/en/tool_analytics.php
+++ b/admin/tool/analytics/lang/en/tool_analytics.php
@@ -24,6 +24,7 @@
$string['accuracy'] = 'Accuracy';
$string['allpredictions'] = 'All predictions';
+$string['alltimesplittingmethods'] = 'All time-splitting methods';
$string['analysingsitedata'] = 'Analysing the site';
$string['analyticmodels'] = 'Analytics models';
$string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is recommended to run these actions from the command line.';
@@ -36,6 +37,7 @@ $string['clienablemodel'] = 'You can enable the model by selecting a time-splitt
$string['clievaluationandpredictions'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. You can allow these processes to be executed manually via the web interface by disabling the \'onlycli\' analytics setting.';
$string['clievaluationandpredictionsnoadmin'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. It may be enabled by a site administrator.';
$string['createmodel'] = 'Create model';
+$string['currenttimesplitting'] = 'Current time-splitting method';
$string['delete'] = 'Delete';
$string['deletemodelconfirmation'] = 'Are you sure you want to delete "{$a}"? These changes can not be reverted.';
$string['disabled'] = 'Disabled';
@@ -111,6 +113,7 @@ $string['predictionprocessfinished'] = 'Prediction process finished';
$string['previouspage'] = 'Previous page';
$string['samestartdate'] = 'Current start date is good';
$string['sameenddate'] = 'Current end date is good';
+$string['selecttimesplittingforevaluation'] = 'Select the time-splitting method you want to use to evaluate the model configuration.';
$string['target'] = 'Target';
$string['target_help'] = 'The target is what the model will predict.';
$string['target_link'] = 'Targets';
diff --git a/admin/tool/analytics/model.php b/admin/tool/analytics/model.php
index ab2fe61796a..7e9f528a640 100644
--- a/admin/tool/analytics/model.php
+++ b/admin/tool/analytics/model.php
@@ -172,7 +172,19 @@ switch ($action) {
$mode = optional_param('mode', false, PARAM_ALPHANUM);
if ($mode == 'trainedmodel') {
$options['mode'] = 'trainedmodel';
+ } else {
+
+ // All is the default in core_analytics\model::evaluate() as well.
+ $timesplitting = optional_param('timesplitting', 'all', PARAM_ALPHANUMEXT);
+ if ($timesplitting === 'current') {
+ $options['timesplitting'] = \core_analytics\manager::get_time_splitting($model->get_model_obj()->timesplitting);
+ } else if ($timesplitting !== 'all') {
+ $options['timesplitting'] = \core_analytics\manager::get_time_splitting(
+ \tool_analytics\output\helper::option_to_class($timesplitting)
+ );
+ }
}
+
$results = $model->evaluate($options);
// We reset the theme and the output as some indicators may be using external functions
diff --git a/admin/tool/analytics/templates/evaluation_mode_selection.mustache b/admin/tool/analytics/templates/evaluation_mode_selection.mustache
deleted file mode 100644
index e9b32ce80ef..00000000000
--- a/admin/tool/analytics/templates/evaluation_mode_selection.mustache
+++ /dev/null
@@ -1,42 +0,0 @@
-{{!
- This file is part of Moodle - http://moodle.org/
-
- 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.
-
- 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 Moodle. If not, see