diff --git a/mod/quiz/report/statistics/lang/en/quiz_statistics.php b/mod/quiz/report/statistics/lang/en/quiz_statistics.php index 98f2b937442..d0686027fa5 100644 --- a/mod/quiz/report/statistics/lang/en/quiz_statistics.php +++ b/mod/quiz/report/statistics/lang/en/quiz_statistics.php @@ -64,7 +64,10 @@ $string['kurtosis'] = 'Score distribution kurtosis (for {$a})'; $string['lastattempts'] = 'last attempt'; $string['lastattemptsavg'] = 'Average grade of last attempts'; $string['lastcalculated'] = 'Last calculated {$a->lastcalculated} ago there have been {$a->count} attempts since then.'; +$string['maximumfacility'] = 'Maximum facility'; $string['median'] = 'Median grade (for {$a})'; +$string['medianfacility'] = 'Median facility'; +$string['minimumfacility'] = 'Minimum facility'; $string['modelresponse'] = 'Model response'; $string['nameforvariant'] = 'Variant {$a->variant} of {$a->name}'; $string['negcovar'] = 'Negative covariance of grade with total attempt grade'; diff --git a/mod/quiz/report/statistics/report.php b/mod/quiz/report/statistics/report.php index fe09d91dc80..148ea39bf8c 100644 --- a/mod/quiz/report/statistics/report.php +++ b/mod/quiz/report/statistics/report.php @@ -38,6 +38,8 @@ require_once($CFG->dirroot . '/mod/quiz/report/statistics/statisticslib.php'); */ class quiz_statistics_report extends quiz_default_report { + const SUBQ_AND_VARIANT_ROW_LIMIT = 10; + /** * @var context_module */ @@ -413,39 +415,94 @@ class quiz_statistics_report extends quiz_default_report { // Output the data for these question statistics. $this->table->add_data_keyed($this->table->format_row($questionstat)); if (count($questionstat->variantstats) > 1) { - ksort($questionstat->variantstats); - foreach ($questionstat->variantstats as $variantstat) { - $this->table->add_data_keyed($this->table->format_row($variantstat)); + if (count($questionstat->variantstats) > static::SUBQ_AND_VARIANT_ROW_LIMIT) { + $statstoadd = $this->find_min_median_and_max_facility_stats_objects($questionstat->variantstats); + } else { + ksort($questionstat->variantstats); + $statstoadd = $questionstat->variantstats; } + $this->add_array_of_rows_to_table($statstoadd); } if (empty($questionstat->subquestions)) { continue; } - // And its subquestions, if it has any. + // And its sub-questions, if it has any. $subitemstodisplay = explode(',', $questionstat->subquestions); + + // We need to get all variants out of sub-questions to count them and possibly find min, median and max. $displayorder = 1; + $subqvariants = array(); foreach ($subitemstodisplay as $subitemid) { - $subquestionstats[$subitemid]->maxmark = $questionstat->maxmark; - $subquestionstats[$subitemid]->subqdisplayorder = $displayorder; - $subquestionstats[$subitemid]->question->number = $questionstat->question->number; - $this->table->add_data_keyed($this->table->format_row($subquestionstats[$subitemid])); if (count($subquestionstats[$subitemid]->variantstats) > 1) { ksort($subquestionstats[$subitemid]->variantstats); foreach ($subquestionstats[$subitemid]->variantstats as $variantstat) { $variantstat->subqdisplayorder = $displayorder; $variantstat->question->number = $questionstat->question->number; - $this->table->add_data_keyed($this->table->format_row($variantstat)); + $subqvariants[] = $variantstat; } } $displayorder++; } + if (count($subqvariants) > static::SUBQ_AND_VARIANT_ROW_LIMIT) { + // Too many variants from randomly selected questions. + $toadd = $this->find_min_median_and_max_facility_stats_objects($subqvariants); + $this->add_array_of_rows_to_table($toadd); + } else if (count($subitemstodisplay) > static::SUBQ_AND_VARIANT_ROW_LIMIT) { + // Too many randomly selected questions. + $toadd = $this->find_min_median_and_max_facility_stats_objects($subitemstodisplay); + $this->add_array_of_rows_to_table($toadd); + } else { + foreach ($subitemstodisplay as $subitemid) { + $subquestionstats[$subitemid]->maxmark = $questionstat->maxmark; + $subquestionstats[$subitemid]->subqdisplayorder = $displayorder; + $subquestionstats[$subitemid]->question->number = $questionstat->question->number; + $this->table->add_data_keyed($this->table->format_row($subquestionstats[$subitemid])); + if (count($subquestionstats[$subitemid]->variantstats) > 1) { + ksort($subquestionstats[$subitemid]->variantstats); + foreach ($subquestionstats[$subitemid]->variantstats as $variantstat) { + $this->table->add_data_keyed($this->table->format_row($variantstat)); + } + } + } + } + } $this->table->finish_output(!$this->table->is_downloading()); } + protected function find_min_median_and_max_facility_stats_objects($questionstats) { + $facilities = array(); + foreach ($questionstats as $key => $questionstat) { + $facilities[$key] = (float)$questionstat->facility; + } + asort($facilities); + $facilitykeys = array_keys($facilities); + $keyformin = $facilitykeys[0]; + $keyformedian = $facilitykeys[(int)(round(count($facilitykeys) / 2)-1)]; + $keyformax = $facilitykeys[count($facilitykeys) - 1]; + $toreturn = array(); + foreach (array($keyformin => 'minimumfacility', + $keyformedian => 'medianfacility', + $keyformax => 'maximumfacility') as $key => $stringid) { + $questionstats[$key]->minmedianmaxnotice = get_string($stringid, 'quiz_statistics'); + $toreturn[] = $questionstats[$key]; + } + return $toreturn; + } + + + /** + * @param \core_question\statistics\questions\calculator $statstoadd + */ + protected function add_array_of_rows_to_table($statstoadd) { + foreach ($statstoadd as $stattoadd) { + $this->table->add_data_keyed($this->table->format_row($stattoadd)); + } + } + /** * Output the table of overall quiz statistics. * @param array $quizinfo as returned by {@link get_formatted_quiz_info_data()}. diff --git a/mod/quiz/report/statistics/statistics_table.php b/mod/quiz/report/statistics/statistics_table.php index c295e513cff..14496161d89 100644 --- a/mod/quiz/report/statistics/statistics_table.php +++ b/mod/quiz/report/statistics/statistics_table.php @@ -138,7 +138,7 @@ class quiz_statistics_table extends flexible_table { protected function col_number($questionstat) { $number = $questionstat->question->number; - if ($questionstat->subquestion) { + if (isset($questionstat->subqdisplayorder)) { $number = $number . '.'.$questionstat->subqdisplayorder; } @@ -213,6 +213,10 @@ class quiz_statistics_table extends flexible_table { $name = html_writer::tag('div', $name, array('class' => 'dubious')); } + if (!empty($questionstat->minmedianmaxnotice)) { + $name = $questionstat->minmedianmaxnotice . '
' . $name; + } + return $name; } diff --git a/question/classes/statistics/questions/calculated.php b/question/classes/statistics/questions/calculated.php index 3d8b652f6a2..198212a645c 100644 --- a/question/classes/statistics/questions/calculated.php +++ b/question/classes/statistics/questions/calculated.php @@ -55,6 +55,12 @@ class calculated { */ public $subquestion = false; + /** + * @var string if this stat has been picked as a min, median or maximum facility value then this string says which stat this + * is. + */ + public $minmedianmaxnotice = ''; + /** * @var int total attempts at this question. */