MDL-57791 analytics: No UI in calculables APIs

This commit is contained in:
David Monllao 2017-06-13 13:39:00 +02:00
parent 3a217fc394
commit 27ae9af4ba
9 changed files with 152 additions and 38 deletions

View File

@ -35,6 +35,12 @@ defined('MOODLE_INTERNAL') || die();
*/
abstract class calculable {
const OUTCOME_NEUTRAL = 0;
const OUTCOME_VERY_POSITIVE = 1;
const OUTCOME_OK = 2;
const OUTCOME_NEGATIVE = 3;
const OUTCOME_VERY_NEGATIVE = 4;
/**
* @var array[]
*/
@ -81,6 +87,30 @@ abstract class calculable {
$this->sampledata = array();
}
/**
* Returns the visible value of the calculated value.
*
* @param float $value
* @param string|false $subtype
* @return string
*/
public function get_display_value($value, $subtype = false) {
return $value;
}
/**
* Returns how good the calculated value is.
*
* Use one of \core_analytics\calculable::OUTCOME_* values.
*
* @param float $value
* @param string|false $subtype
* @return int
*/
public function get_calculation_outcome($value, $subtype = false) {
throw new \coding_exception('Please overwrite get_calculation_outcome method');
}
/**
* Retrieve the specified element associated to $sampleid.
*

View File

@ -41,6 +41,13 @@ abstract class binary extends discrete {
return array(0);
}
/**
* get_display_value
*
* @param float $value
* @param string $subtype
* @return string
*/
public function get_display_value($value, $subtype = false) {
// No subtypes for binary values by default.
@ -53,13 +60,20 @@ abstract class binary extends discrete {
}
}
public function get_value_style($value, $subtype = false) {
/**
* get_calculation_outcome
*
* @param float $value
* @param string $subtype
* @return int
*/
public function get_calculation_outcome($value, $subtype = false) {
// No subtypes for binary values by default.
if ($value == -1) {
return 'alert alert-warning';
return self::OUTCOME_NEGATIVE;
} else if ($value == 1) {
return 'alert alert-info';
return self::OUTCOME_OK;
} else {
throw new \moodle_exception('errorpredictionformat', 'analytics');
}

View File

@ -67,11 +67,11 @@ abstract class discrete extends base {
/**
* Returns the value to display when the prediction is $value.
*
* @param mixed $value
* @param float $value
* @param string $subtype
* @return void
* @return string
*/
public function get_display_value($value, $subtype) {
public function get_display_value($value, $subtype = false) {
$displayvalue = array_search($subtype, static::get_classes());
@ -81,10 +81,17 @@ abstract class discrete extends base {
return $displayvalue;
}
public function get_display_style($value, $subtype) {
/**
* get_display_style
*
* @param float $ignoredvalue
* @param string $ignoredsubtype
* @return int
*/
public function get_display_style($ignoredvalue, $ignoredsubtype) {
// No style attached to indicators classes, they are what they are, a cat,
// a horse or a sandwich, they are not good or bad.
return '';
return \core_analytics\calculable::OUTCOME_NEUTRAL;
}
protected function to_features($calculatedvalues) {

View File

@ -64,16 +64,30 @@ abstract class linear extends base {
return true;
}
/**
* get_display_value
*
* @param float $value
* @param string $subtype
* @return string
*/
public function get_display_value($value, $subtype = false) {
$diff = static::get_max_value() - static::get_min_value();
return round(100 * ($value - static::get_min_value()) / $diff) . '%';
}
public function get_value_style($value, $subtype = false) {
/**
* get_calculation_outcome
*
* @param float $value
* @param string $subtype
* @return int
*/
public function get_calculation_outcome($value, $subtype = false) {
if ($value < 0) {
return 'alert alert-warning';
return self::OUTCOME_NEGATIVE;
} else {
return 'alert alert-info';
return self::OUTCOME_OK;
}
}

View File

@ -120,14 +120,6 @@ abstract class base extends \core_analytics\calculable {
);
}
public function get_display_value($value) {
return $value;
}
public function get_value_style($value) {
throw new \coding_exception('Please overwrite \core_analytics\local\target\base::get_value_style');
}
/**
* Callback to execute once a prediction has been returned from the predictions processor.
*

View File

@ -62,7 +62,7 @@ abstract class binary extends discrete {
return array(0);
}
public function get_value_style($value) {
public function get_calculation_outcome($value, $ignoredsubtype = false) {
if (!self::is_a_class($value)) {
throw new \moodle_exception('errorpredictionformat', 'analytics');
@ -71,14 +71,14 @@ abstract class binary extends discrete {
if (in_array($value, $this->ignored_predicted_classes())) {
// Just in case, if it is ignored the prediction should not even be recorded but if it would, it is ignored now,
// which should mean that is it nothing serious.
return 'alert alert-success';
return self::OUTCOME_VERY_POSITIVE;
}
// Default binaries are danger when prediction = 1.
// By default binaries are danger when prediction = 1.
if ($value) {
return 'alert alert-danger';
return self::OUTCOME_VERY_NEGATIVE;
}
return 'alert alert-success';
return self::OUTCOME_VERY_POSITIVE;
}
protected static function classes_description() {

View File

@ -44,7 +44,14 @@ abstract class discrete extends base {
return (in_array($class, static::get_classes()));
}
public function get_display_value($value) {
/**
* get_display_value
*
* @param float $value
* @param string $subtype
* @return string
*/
public function get_display_value($value, $ignoredsubtype = false) {
if (!self::is_a_class($value)) {
throw new \moodle_exception('errorpredictionformat', 'analytics');
@ -66,7 +73,14 @@ abstract class discrete extends base {
return $descriptions[$key];
}
public function get_value_style($value) {
/**
* get_calculation_outcome
*
* @param float $value
* @param string $ignoredsubtype
* @return int
*/
public function get_calculation_outcome($value, $ignoredsubtype = false) {
if (!self::is_a_class($value)) {
throw new \moodle_exception('errorpredictionformat', 'analytics');
@ -74,16 +88,16 @@ abstract class discrete extends base {
if (in_array($value, $this->ignored_predicted_classes())) {
// Just in case, if it is ignored the prediction should not even be recorded.
return '';
return self::OUTCOME_OK;
}
debugging('Please overwrite \core_analytics\local\target\discrete::get_value_style, all your target classes are styled ' .
debugging('Please overwrite \core_analytics\local\target\discrete::get_calculation_outcome, all your target classes are styled ' .
'the same way otherwise', DEBUG_DEVELOPER);
return 'alert alert-danger';
return self::OUTCOME_OK;
}
/**
* Returns the target discrete values.
* Returns all the possible values the target calculation can return.
*
* Only useful for targets using discrete values, must be overwriten if it is the case.
*
@ -91,12 +105,20 @@ abstract class discrete extends base {
*/
public static function get_classes() {
// Coding exception as this will only be called if this target have non-linear values.
throw new \coding_exception('Overwrite get_classes() and return an array with the different target classes');
throw new \coding_exception('Overwrite get_classes() and return an array with the different values the ' .
'target calculation can return');
}
/**
* Returns descriptions for each of the values the target calculation can return.
*
* The array indexes should match self::get_classes indexes.
*
* @return array
*/
protected static function classes_description() {
throw new \coding_exception('Overwrite classes_description() and return an array with the target classes description and ' .
'indexes matching self::get_classes');
throw new \coding_exception('Overwrite classes_description() and return an array with a description for each of the ' .
'different values the target calculation can return. Indexes should match self::get_classes indexes');
}
/**

View File

@ -40,14 +40,14 @@ abstract class linear extends base {
throw new \coding_exception('Sorry, this version\'s prediction processors only support targets with binary values.');
}
public function get_value_style($value) {
public function get_calculated_outcome($value, $ignoredsubtype = false) {
// This is very generic, targets will probably be interested in overwriting this.
$diff = static::get_max_value() - static::get_min_value();
if (($value - static::get_min_value()) / $diff >= 0.5) {
return 'alert alert-success';
return self::OUTCOME_VERY_POSITIVE;
}
return 'alert alert-danger';
return self::OUTCOME_VERY_NEGATIVE;
}
/**

View File

@ -72,7 +72,7 @@ class insight implements \renderable, \templatable {
$predictedvalue = $this->prediction->get_prediction_data()->prediction;
$predictionid = $this->prediction->get_prediction_data()->id;
$data->predictiondisplayvalue = $this->model->get_target()->get_display_value($predictedvalue);
$data->predictionstyle = $this->model->get_target()->get_value_style($predictedvalue);
$data->predictionstyle = $this->get_calculation_style($this->model->get_target(), $predictedvalue);
$actions = $this->model->get_target()->prediction_actions($this->prediction);
if ($actions) {
@ -108,11 +108,46 @@ class insight implements \renderable, \templatable {
$obj = new \stdClass();
$obj->name = forward_static_call(array($calculation->indicator, 'get_name'), $calculation->subtype);
$obj->displayvalue = $calculation->indicator->get_display_value($calculation->value, $calculation->subtype);
$obj->style = $calculation->indicator->get_value_style($calculation->value, $calculation->subtype);
$obj->style = $this->get_calculation_style($calculation->indicator, $calculation->value, $calculation->subtype);
$data->calculations[] = $obj;
}
return $data;
}
/**
* Returns a CSS class from the calculated value outcome.
*
* @param \core_analytics\calculable $calculable
* @param mixed $value
* @param string|false $subtype
* @return string
*/
protected function get_calculation_style(\core_analytics\calculable $calculable, $value, $subtype = false) {
$outcome = $calculable->get_calculation_outcome($value, $subtype);
switch ($outcome) {
case \core_analytics\calculable::OUTCOME_NEUTRAL:
$style = '';
break;
case \core_analytics\calculable::OUTCOME_VERY_POSITIVE:
$style = 'alert alert-success';
break;
case \core_analytics\calculable::OUTCOME_OK:
$style = 'alert alert-info';
break;
case \core_analytics\calculable::OUTCOME_NEGATIVE:
$style = 'alert alert-warning';
break;
case \core_analytics\calculable::OUTCOME_VERY_NEGATIVE:
$style = 'alert alert-danger';
break;
default:
throw new \coding_exception('The outcome returned by ' . get_class($calculable) . '::get_calculation_outcome is ' .
'not one of the accepted values. Please use \core_analytics\calculable::OUTCOME_VERY_POSITIVE, ' .
'\core_analytics\calculable::OUTCOME_OK, \core_analytics\calculable::OUTCOME_NEGATIVE or ' .
'\core_analytics\calculable::OUTCOME_VERY_NEGATIVE');
}
return $style;
}
}