mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
MDL-57791 insights: Clarify insights-prediction boundaries
This commit is contained in:
parent
1a8461390b
commit
f9e7447f42
@ -57,6 +57,11 @@ class no_teaching extends \core_analytics\local\target\binary {
|
||||
$sampledata = $prediction->get_sample_data();
|
||||
$course = $sampledata['course'];
|
||||
|
||||
$url = new \moodle_url('/course/view.php', array('id' => $course->id));
|
||||
$pix = new \pix_icon('i/course', get_string('enrolledusers', 'enrol'));
|
||||
$actions['viewcourse'] = new \core_analytics\prediction_action('viewcourse', $prediction,
|
||||
$url, $pix, get_string('view'));
|
||||
|
||||
if (has_capability('moodle/course:enrolreview', $sampledata['context'])) {
|
||||
$url = new \moodle_url('/enrol/users.php', array('id' => $course->id));
|
||||
$pix = new \pix_icon('i/enrolusers', get_string('enrolledusers', 'enrol'));
|
||||
|
@ -56,6 +56,7 @@ class models_list implements \renderable, \templatable {
|
||||
$modeldata = $model->export();
|
||||
|
||||
// Model predictions list.
|
||||
if ($model->uses_insights()) {
|
||||
$predictioncontexts = $model->get_predictions_contexts();
|
||||
if ($predictioncontexts) {
|
||||
|
||||
@ -67,17 +68,36 @@ class models_list implements \renderable, \templatable {
|
||||
unset($predictioncontexts[$contextid]);
|
||||
continue;
|
||||
}
|
||||
$predictioncontexts[$contextid] = shorten_text($context->get_context_name(true, true), 90);
|
||||
|
||||
// Special name for system level predictions as showing "System is not visually nice".
|
||||
if ($contextid == SYSCONTEXTID) {
|
||||
$contextname = get_string('allpredictions', 'tool_models');
|
||||
} else {
|
||||
$contextname = shorten_text($context->get_context_name(true, true), 90);
|
||||
}
|
||||
$predictioncontexts[$contextid] = $contextname;
|
||||
}
|
||||
\core_collator::asort($predictioncontexts);
|
||||
|
||||
if (!empty($predictioncontexts)) {
|
||||
$url = new \moodle_url('/report/insights/insights.php', array('modelid' => $model->get_id()));
|
||||
$singleselect = new \single_select($url, 'contextid', $predictioncontexts);
|
||||
$modeldata->predictions = $singleselect->export_for_template($output);
|
||||
$modeldata->insights = $singleselect->export_for_template($output);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($modeldata->insights)) {
|
||||
if ($model->any_prediction_obtained()) {
|
||||
$modeldata->noinsights = get_string('noinsights', 'analytics');
|
||||
} else {
|
||||
$modeldata->noinsights = get_string('nopredictionsyet', 'analytics');
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$modeldata->noinsights = get_string('noinsightsmodel', 'analytics');
|
||||
}
|
||||
|
||||
// Actions.
|
||||
$actionsmenu = new \action_menu();
|
||||
$actionsmenu->set_menu_trigger(get_string('actions'));
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
$string['accuracy'] = 'Accuracy';
|
||||
$string['allindicators'] = 'All indicators';
|
||||
$string['allpredictions'] = 'All predictions';
|
||||
$string['analysingsitedata'] = 'Analysing the site';
|
||||
$string['analyticmodels'] = 'Analytic models';
|
||||
$string['bettercli'] = 'To evaluate models and to get predictions are heavy processes, it is better to run them through command line interface';
|
||||
@ -53,6 +54,7 @@ $string['getpredictions'] = 'Get predictions';
|
||||
$string['goodmodel'] = 'This is a good model and it can be used to predict, enable it to start getting predictions.';
|
||||
$string['indicators'] = 'Indicators';
|
||||
$string['info'] = 'Info';
|
||||
$string['insights'] = 'Insights';
|
||||
$string['labelstudentdropoutyes'] = 'Student at risk of dropping out';
|
||||
$string['labelstudentdropoutno'] = 'Not at risk';
|
||||
$string['labelteachingyes'] = 'Users with teaching capabilities have access to the course';
|
||||
@ -88,6 +90,5 @@ $string['trainingprocessfinished'] = 'Training process finished';
|
||||
$string['trainingresults'] = 'Training results';
|
||||
$string['trainmodels'] = 'Train models';
|
||||
$string['viewlog'] = 'Log';
|
||||
$string['viewpredictions'] = 'View model predictions';
|
||||
$string['weeksenddateautomaticallyset'] = 'End date automatically set based on start date and the number of sections';
|
||||
$string['weeksenddatedefault'] = 'End date would be automatically calculated from the course start date';
|
||||
|
@ -45,7 +45,7 @@
|
||||
<th scope="col">{{#str}}enabled, tool_models{{/str}}</th>
|
||||
<th scope="col">{{#str}}indicators, tool_models{{/str}}</th>
|
||||
<th scope="col">{{#str}}modeltimesplitting, tool_models{{/str}}</th>
|
||||
<th scope="col">{{#str}}viewpredictions, tool_models{{/str}}</th>
|
||||
<th scope="col">{{#str}}insights, tool_models{{/str}}</th>
|
||||
<th scope="col">{{#str}}actions{{/str}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -72,12 +72,13 @@
|
||||
{{#timesplitting}}{{timesplitting}}{{/timesplitting}}{{^timesplitting}}{{#str}}notdefined, tool_models{{/str}}{{/timesplitting}}
|
||||
</td>
|
||||
<td>
|
||||
{{#predictions}}
|
||||
{{! models_list renderer is responsible of sending one or the other}}
|
||||
{{#insights}}
|
||||
{{> core/single_select }}
|
||||
{{/predictions}}
|
||||
{{^predictions}}
|
||||
{{#str}}nopredictionsyet, analytics{{/str}}
|
||||
{{/predictions}}
|
||||
{{/insights}}
|
||||
{{#noinsights}}
|
||||
{{.}}
|
||||
{{/noinsights}}
|
||||
</td>
|
||||
<td>
|
||||
{{#actions}}
|
||||
|
@ -36,8 +36,6 @@ require_once($CFG->dirroot . '/lib/gradelib.php');
|
||||
*/
|
||||
class course implements \core_analytics\analysable {
|
||||
|
||||
const MIN_STUDENT_LOGS_PERCENT = 90;
|
||||
|
||||
protected static $instances = array();
|
||||
|
||||
protected $studentroles = [];
|
||||
|
@ -83,6 +83,17 @@ abstract class base extends \core_analytics\calculable {
|
||||
*/
|
||||
abstract protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);
|
||||
|
||||
/**
|
||||
* Is this target generating insights?
|
||||
*
|
||||
* Defaults to true.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function uses_insights() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on facts (processed by machine learning backends) by default.
|
||||
*
|
||||
|
@ -89,6 +89,9 @@ class model {
|
||||
|
||||
if (is_scalar($model)) {
|
||||
$model = $DB->get_record('analytics_models', array('id' => $model));
|
||||
if (!$model) {
|
||||
throw new \moodle_exception('errorunexistingmodel', 'analytics', '', $model);
|
||||
}
|
||||
}
|
||||
$this->model = $model;
|
||||
}
|
||||
@ -821,6 +824,31 @@ class model {
|
||||
return $DB->get_records_sql($sql, array($this->model->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this model generated predictions?
|
||||
*
|
||||
* We don't check analytics_predictions table because targets have the ability to
|
||||
* ignore some predicted values, if that is the case predictions are not even stored
|
||||
* in db.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function any_prediction_obtained() {
|
||||
global $DB;
|
||||
return $DB->record_exists('analytics_predict_ranges',
|
||||
array('modelid' => $this->model->id, 'timesplitting' => $this->model->timesplitting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this model generates insights or not (defined by the model's target).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function uses_insights() {
|
||||
$target = $this->get_target();
|
||||
return $target::uses_insights();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether predictions exist for this context.
|
||||
*
|
||||
|
@ -42,6 +42,7 @@ $string['errorpredictwrongformat'] = 'The predictions processor return can not b
|
||||
$string['errorprocessornotready'] = 'The selected predictions processor is not ready: {$a}';
|
||||
$string['errorsamplenotavailable'] = 'The predicted sample is not available anymore';
|
||||
$string['errorunexistingtimesplitting'] = 'The selected time splitting method is not available';
|
||||
$string['errorunexistingmodel'] = 'Unexisting model {$a}';
|
||||
$string['errorunknownaction'] = 'Unknown action';
|
||||
$string['eventactionclicked'] = 'Prediction action clicked';
|
||||
$string['indicator:accessesafterend'] = 'Accesses after the end date';
|
||||
@ -61,6 +62,8 @@ $string['modeloutputdirinfo'] = 'Directory where prediction processors store all
|
||||
$string['nocourses'] = 'No courses to analyse';
|
||||
$string['nocoursestart'] = 'No course start';
|
||||
$string['nodata'] = 'No data available';
|
||||
$string['noinsightsmodel'] = 'This model does not generate insights';
|
||||
$string['noinsights'] = 'No insights reported';
|
||||
$string['nonewdata'] = 'No new data available';
|
||||
$string['nonewtimeranges'] = 'No new time ranges, nothing to predict';
|
||||
$string['nopredictionsyet'] = 'No predictions available yet';
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Prediction view page.
|
||||
* Single insight view page.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
@ -27,13 +27,13 @@ namespace report_insights\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Prediction view page.
|
||||
* Single insight view page.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class prediction implements \renderable, \templatable {
|
||||
class insight implements \renderable, \templatable {
|
||||
|
||||
/**
|
||||
* @var \core_analytics\model
|
@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Predictions list page.
|
||||
* Insights list page.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
@ -27,13 +27,13 @@ namespace report_insights\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Shows report_insights predictions list.
|
||||
* Shows report_insights insights list.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class predictions_list implements \renderable, \templatable {
|
||||
class insights_list implements \renderable, \templatable {
|
||||
|
||||
/**
|
||||
* @var \core_analytics\model
|
||||
@ -67,17 +67,29 @@ class predictions_list implements \renderable, \templatable {
|
||||
|
||||
$data = new \stdClass();
|
||||
|
||||
if ($this->model->uses_insights()) {
|
||||
$predictions = $this->model->get_predictions($this->context);
|
||||
|
||||
$data->predictions = array();
|
||||
$data->insights = array();
|
||||
foreach ($predictions as $prediction) {
|
||||
$predictionrenderable = new \report_insights\output\prediction($prediction, $this->model);
|
||||
$data->predictions[] = $predictionrenderable->export_for_template($output);
|
||||
$insightrenderable = new \report_insights\output\insight($prediction, $this->model);
|
||||
$data->insights[] = $insightrenderable->export_for_template($output);
|
||||
}
|
||||
|
||||
if (empty($data->predictions)) {
|
||||
$notification = new \core\output\notification(get_string('nopredictionsyet', 'analytics'));
|
||||
$data->nopredictions = $notification->export_for_template($output);
|
||||
if (empty($data->insights)) {
|
||||
if ($this->model->any_prediction_obtained()) {
|
||||
$data->noinsights = get_string('noinsights', 'analytics');
|
||||
} else {
|
||||
$data->noinsights = get_string('nopredictionsyet', 'analytics');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$data->noinsights = get_string('noinsights', 'analytics');
|
||||
}
|
||||
|
||||
if (!empty($data->noinsights)) {
|
||||
$notification = new \core\output\notification($data->noinsights);
|
||||
$data->noinsights = $notification->export_for_template($output);
|
||||
}
|
||||
|
||||
if ($this->othermodels) {
|
@ -40,25 +40,25 @@ use renderable;
|
||||
class renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Renders the list of predictions
|
||||
* Renders the list of insights
|
||||
*
|
||||
* @param renderable $renderable
|
||||
* @return string HTML
|
||||
*/
|
||||
protected function render_predictions_list(renderable $renderable) {
|
||||
protected function render_insights_list(renderable $renderable) {
|
||||
$data = $renderable->export_for_template($this);
|
||||
return parent::render_from_template('report_insights/predictions_list', $data);
|
||||
return parent::render_from_template('report_insights/insights_list', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a prediction
|
||||
* Renders an insight
|
||||
*
|
||||
* @param renderable $renderable
|
||||
* @return string HTML
|
||||
*/
|
||||
protected function render_prediction(renderable $renderable) {
|
||||
protected function render_insight(renderable $renderable) {
|
||||
$data = $renderable->export_for_template($this);
|
||||
return parent::render_from_template('report_insights/prediction_details', $data);
|
||||
return parent::render_from_template('report_insights/insight_details', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,12 +82,12 @@ class renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Model without predictions info.
|
||||
* Model without insights info.
|
||||
*
|
||||
* @param \context $context
|
||||
* @return string HTML
|
||||
*/
|
||||
public function render_no_predictions(\context $context) {
|
||||
public function render_no_insights(\context $context) {
|
||||
global $OUTPUT, $PAGE;
|
||||
|
||||
// We don't want to disclose the name of the model if it has not been enabled.
|
||||
@ -95,7 +95,27 @@ class renderer extends plugin_renderer_base {
|
||||
$PAGE->set_heading($context->get_context_name());
|
||||
|
||||
$output = $OUTPUT->header();
|
||||
$output .= $OUTPUT->notification(get_string('nopredictionsyet', 'analytics'), \core\output\notification::NOTIFY_INFO);
|
||||
$output .= $OUTPUT->notification(get_string('noinsights', 'analytics'), \core\output\notification::NOTIFY_INFO);
|
||||
$output .= $OUTPUT->footer();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Model which target does not generate insights.
|
||||
*
|
||||
* @param \context $context
|
||||
* @return string HTML
|
||||
*/
|
||||
public function render_no_insights_model(\context $context) {
|
||||
global $OUTPUT, $PAGE;
|
||||
|
||||
// We don't want to disclose the name of the model if it has not been enabled.
|
||||
$PAGE->set_title($context->get_context_name());
|
||||
$PAGE->set_heading($context->get_context_name());
|
||||
|
||||
$output = $OUTPUT->header();
|
||||
$output .= $OUTPUT->notification(get_string('noinsightsmodel', 'analytics'), \core\output\notification::NOTIFY_INFO);
|
||||
$output .= $OUTPUT->footer();
|
||||
|
||||
return $output;
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* View model predictions.
|
||||
* View model insights.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
@ -64,9 +64,9 @@ $PAGE->set_pagelayout('report');
|
||||
|
||||
$renderer = $PAGE->get_renderer('report_insights');
|
||||
|
||||
// No models with predictions available at this context level.
|
||||
// No models with insights available at this context level.
|
||||
if (!$modelid) {
|
||||
echo $renderer->render_no_predictions($context);
|
||||
echo $renderer->render_no_insights($context);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -77,18 +77,22 @@ $insightinfo->contextname = $context->get_context_name();
|
||||
$insightinfo->insightname = $model->get_target()->get_name();
|
||||
$title = get_string('insightinfo', 'analytics', $insightinfo);
|
||||
|
||||
|
||||
if (!$model->is_enabled() && !has_capability('moodle/analytics:managemodels', $context)) {
|
||||
echo $renderer->render_model_disabled($insightinfo);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!$model->uses_insights()) {
|
||||
echo $renderer->render_no_insights_model($context);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($title);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$renderable = new \report_insights\output\predictions_list($model, $context, $othermodels);
|
||||
$renderable = new \report_insights\output\insights_list($model, $context, $othermodels);
|
||||
echo $renderer->render($renderable);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -25,9 +25,9 @@
|
||||
|
||||
$string['disabledmodel'] = 'Sorry, this model has been disabled by the administrator';
|
||||
$string['errorpredictionnotfound'] = 'Prediction not found';
|
||||
$string['insight'] = 'Insight';
|
||||
$string['insights'] = 'Insights';
|
||||
$string['pluginname'] = 'Insights';
|
||||
$string['prediction'] = 'Prediction';
|
||||
$string['predictiondetails'] = 'Prediction details';
|
||||
$string['predictions'] = 'Predictions';
|
||||
$string['selectotherinsights'] = 'Select other insights...';
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* View a prediction.
|
||||
* View an insight.
|
||||
*
|
||||
* @package report_insights
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
@ -68,12 +68,17 @@ if (!$modelready && !has_capability('moodle/analytics:managemodels', $context))
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!$model->uses_insights()) {
|
||||
echo $renderer->render_no_insights_model($context);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($title);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$renderable = new \report_insights\output\prediction($prediction, $model);
|
||||
$renderable = new \report_insights\output\insight($prediction, $model);
|
||||
echo $renderer->render($renderable);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -15,9 +15,9 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template report_insights/prediction
|
||||
@template report_insights/insight
|
||||
|
||||
Template for a prediction.
|
||||
Template for a insight.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
@ -15,7 +15,7 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template report_insights/prediction_details
|
||||
@template report_insights/insight_details
|
||||
|
||||
Actions panel at the bottom of the assignment grading UI.
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
}}
|
||||
|
||||
<h2>{{#str}}prediction, report_insights{{/str}}</h2>
|
||||
{{> report_insights/prediction}}
|
||||
{{> report_insights/insight}}
|
||||
|
||||
<h3>{{#str}} predictiondetails, report_insights {{/str}}</h3>
|
||||
<div class="container prediction-calculations m-t-2">
|
@ -15,9 +15,9 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template report_insights/predictions_list
|
||||
@template report_insights/insights_list
|
||||
|
||||
Template for the predictions list.
|
||||
Template for the insights list.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
@ -39,14 +39,14 @@
|
||||
</div>
|
||||
{{/modelselector}}
|
||||
|
||||
<h3>{{#str}} predictions, report_insights {{/str}}</h3>
|
||||
<div class="predictions-list">
|
||||
{{#predictions}}
|
||||
{{> report_insights/prediction}}
|
||||
{{/predictions}}
|
||||
<h3>{{#str}} insights, report_insights {{/str}}</h3>
|
||||
<div class="insights-list">
|
||||
{{#insights}}
|
||||
{{> report_insights/insight}}
|
||||
{{/insights}}
|
||||
</div>
|
||||
{{#nopredictions}}
|
||||
{{#noinsights}}
|
||||
<div class="m-t-2">
|
||||
{{> core/notification_info}}
|
||||
</div>
|
||||
{{/nopredictions}}
|
||||
{{/noinsights}}
|
Loading…
x
Reference in New Issue
Block a user