' : '';
$nobr_start = $is_html ? '' : '';
$nobr_end = $is_html ? '' : '';
// is review allowed? (do this once here, to save time later)
$allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));
// assume penalties column is NOT required
$show_penalties = false;
// initialize $table
unset($table);
$table->border = 1;
$table->width = '100%';
// initialize legend, if necessary
if (!empty($options['reportshowlegend'])) {
$table->legend = array();
}
// headings for name, attempt number, score/grade and penalties
$table->head = array(
get_string("name"),
hotpot_grade_heading($hotpot, $options),
get_string('attempt', 'quiz'),
);
$table->align = array('left', 'center', 'center');
$table->size = array(150, 80, 10);
$table->wrap = array(0, 0, 0);
$table->fontsize = array(0, 0, 0);
// question headings
$this->add_question_headings($questions, $table, 'left', 0, false, 2);
// penalties (not always needed) and raw score
array_push($table->head,
get_string('penalties', 'hotpot'),
get_string('score', 'quiz')
);
array_push($table->align, 'center', 'center');
array_push($table->size, 50, 50);
array_push($table->wrap, 0, 0);
array_push($table->fontsize, 0, 0);
// message strings
$strnoresponse = get_string('noresponse', 'quiz');
// array to map columns onto question ids ($col => $id)
$questionids = array_keys($questions);
// add details of users' responses
foreach ($users as $user) {
// shortcut to user info held in first attempt record
$u = &$user->attempts[0];
if (function_exists("fullname")) {
$name = fullname($u);
} else {
$name = "$u->firstname $u->lastname";
}
if ($is_html) {
$name = ''.$name.'';
}
$grade = isset($user->grade) ? $user->grade : $blank;
foreach ($user->attempts as $attempt) {
$attemptnumber = $attempt->attempt;
if ($allow_review) {
$attemptnumber = ' '.$attemptnumber.'';
}
$cells = array ($name, $grade, $attemptnumber);
// $name and $grade are only printed on first line per user
$name = $blank;
$grade = $blank;
$start_col = count($cells);
foreach ($questionids as $col => $id) {
$cells[$start_col + $col] = "$font_brown($strnoresponse)$font_end";
}
if (isset($attempt->penalties)) {
$show_penalties = true;
$penalties = $attempt->penalties;
} else {
$penalties = $blank;
}
array_push($cells, $penalties, hotpot_format_score($attempt));
// get responses to questions in this attempt
foreach ($attempt->responses as $response) {
// check this question id is OK (should be)
$col = array_search($response->question, $questionids);
if (is_numeric($col)) {
// correct
if ($value = hotpot_strings($response->correct)) {
$this->set_legend($table, $col, $value, $questions[$response->question]);
} else {
$value = "($strnoresponse)";
}
$cell = $font_red.$value.$font_end;
// wrong
if ($value = hotpot_strings($response->wrong)) {
if (isset($table->legend)) {
$values = array();
foreach (explode(',', $value) as $v) {
$this->set_legend($table, $col, $v, $questions[$response->question]);
$values[] = $v;
}
$value = implode(',', $values);
}
$cell .= $br.$font_blue.$value.$font_end;
}
// ignored
if ($value = hotpot_strings($response->ignored)) {
if (isset($table->legend)) {
$values = array();
foreach (explode(',', $value) as $v) {
$this->set_legend($table, $col, $v, $questions[$response->question]);
$values[] = $v;
}
$value = implode(',', $values);
}
$cell .= $br.$font_brown.$value.$font_end;
}
// numeric
if (is_numeric($response->score)) {
if (empty($table->caption)) {
$table->caption = get_string('indivresp', 'quiz');
if ($is_html) {
$table->caption .= helpbutton('responsestable', $table->caption, 'hotpot', true, false, '', true);
}
}
$hints = empty($response->hints) ? 0 : $response->hints;
$clues = empty($response->clues) ? 0 : $response->clues;
$checks = empty($response->checks) ? 0 : $response->checks;
$numeric = $response->score.'% '.$blank.' ('.$hints.','.$clues.','.$checks.')';
$cell .= $br.$nobr_start.$font_green.$numeric.$font_end.$nobr_end;
}
$cells[$start_col + $col] = $cell;
}
}
$table->data[] = $cells;
}
// insert 'tabledivider' between users
$table->data[] = 'hr';
} // end foreach $users
// remove final 'hr' from data rows
array_pop($table->data);
if (!$show_penalties) {
$col = 3 + count($questionids);
$this->remove_column($table, $col);
}
$tables[] = &$table;
}
function create_analysis_table(&$users, &$attempts, &$questions, &$options, &$tables) {
$is_html = ($options['reportformat']=='htm');
// the fields we are interested in, in the order we want them
$fields = array('correct', 'wrong', 'ignored', 'hints', 'clues', 'checks', 'weighting');
$string_fields = array('correct', 'wrong', 'ignored');
$q = array(); // statistics about the $q(uestions)
$f = array(); // statistics about the $f(ields)
////////////////////////////////////////////
// compile the statistics about the questions
////////////////////////////////////////////
foreach ($questions as $id=>$question) {
// extract scores for attempts at this question
$scores = array();
foreach ($question->attempts as $attempt) {
$scores[] = $attempt->score;
}
// sort scores values (in ascending order)
asort($scores);
// get the borderline high and low scores
$count = count($scores);
switch ($count) {
case 0:
$lo_score = 0;
$hi_score = 0;
break;
case 1:
$lo_score = 0;
$hi_score = $scores[0];
break;
default:
$lo_score = $scores[round($count*1/3)];
$hi_score = $scores[round($count*2/3)];
break;
}
// get statistics for each attempt which includes this question
foreach ($question->attempts as $attempt) {
$is_hi_score = ($attempt->score >= $hi_score);
$is_lo_score = ($attempt->score < $lo_score);
// reference to the response to the current question
$response = &$attempt->responses[$id];
// update statistics for fields in this response
foreach($fields as $field) {
if (!isset($q[$id])) {
$q[$id] = array();
}
if (!isset($f[$field])) {
$f[$field] = array('count' => 0);
}
if (!isset($q[$id][$field])) {
$q[$id][$field] = array('count' => 0);
}
$values = explode(',', $response->$field);
$values = array_unique($values);
foreach($values as $value) {
// $value should be an integer (string_id or count)
if (is_numeric($value)) {
$f[$field]['count']++;
if (!isset($q[$id][$field][$value])) {
$q[$id][$field][$value] = 0;
}
$q[$id][$field]['count']++;
$q[$id][$field][$value]++;
}
}
} // end foreach $field
// initialize counters for this question, if necessary
if (!isset($q[$id]['count'])) {
$q[$id]['count'] = array('hi'=>0, 'lo'=>0, 'correct'=>0, 'total'=>0, 'sum'=>0);
}
// increment counters
$q[$id]['count']['sum'] += $response->score;
$q[$id]['count']['total']++;
if ($response->score==100) {
$q[$id]['count']['correct']++;
if ($is_hi_score) {
$q[$id]['count']['hi']++;
} else if ($is_lo_score) {
$q[$id]['count']['lo']++;
}
}
} // end foreach attempt
} // end foreach question
// check we have some details
if (count($q)) {
$showhideid = 'showhide';
// shortcuts for html tags
$bold_start = $is_html ? '' : "";
$bold_end = $is_html ? '' : "";
$div_start = $is_html ? '' : "";
$div_end = $is_html ? '
' : "";
$font_red = $is_html ? '' : '';
$font_blue = $is_html ? '' : '';
$font_green = $is_html ? '' : '';
$font_brown = $is_html ? '' : '';
$font_end = $is_html ? ''."\n" : '';
$br = $is_html ? '
' : "\n";
$space = $is_html ? ' ' : "";
$no_value = $is_html ? '--' : "";
$help_button = $is_html ? helpbutton("discrimination", get_string('discrimination', 'quiz'), "quiz", true, false, "", true) : "";
// table properties
unset($table);
$table->border = 1;
$table->width = '100%';
$table->caption = get_string('itemanal', 'quiz');
if ($is_html) {
$table->caption .= helpbutton('analysistable', $table->caption, 'hotpot', true, false, '', true);
}
// initialize legend, if necessary
if (!empty($options['reportshowlegend'])) {
if (empty($tables) || empty($tables[0]->legend)) {
$table->legend = array();
} else {
$table->legend = $tables[0]->legend;
unset($tables[0]->legend);
}
}
// headings for name, attempt number and score/grade
$table->head = array($space);
$table->align = array('right');
$table->size = array(80);
// question headings
$this->add_question_headings($questions, $table, 'left', 0);
// initialize statistics
$table->stat = array();
$table->statheadercols = array(0);
// add headings for the $foot of the $table
$table->foot = array();
$table->foot[0] = array(get_string('average', 'hotpot'));
$table->foot[1] = array(get_string('percentcorrect', 'quiz'));
$table->foot[2] = array(get_string('discrimination', 'quiz').$help_button);
// maximum discrimination index (also default the default value)
$max_d_index = 10;
////////////////////////////////////////////
// format the statistics into the $table
////////////////////////////////////////////
// add $stat(istics) and $foot of $table
$questionids = array_keys($q);
foreach ($questionids as $col => $id) {
$row = 0;
// print the question text if there is no legend
if (empty($table->legend)) {
// add button to show/hide question text
if (!isset($table->stat[0])) {
$button = $is_html ? hotpot_showhide_button($showhideid) : "";
$table->stat[0] = array(get_string('question', 'quiz').$button);
}
// add the question name/text
$name = hotpot_get_question_name($questions[$id]);
$table->stat[$row++][$col+1] = $div_start.$bold_start.$name.$bold_end.$div_end.$space;
}
// add details about each field
foreach ($fields as $field) {
// check this row is required
if ($f[$field]['count']) {
$values = array();
$string_type = array_search($field, $string_fields);
// get the value of each response to this field
// and the count of that value
foreach ($q[$id][$field] as $value => $count) {
if (is_numeric($value) && $count) {
if (is_numeric($string_type)) {
$value = hotpot_string($value);
$this->set_legend($table, $col, $value, $questions[$id]);
switch ($string_type) {
case 0: // correct
$font_start = $font_red;
break;
case 1: // wrong
$font_start = $font_blue;
break;
case 2: // ignored
$font_start = $font_brown;
break;
}
} else { // numeric field
$font_start = $font_green;
}
$values[] = $font_start.round(100*$count/$q[$id]['count']['total']).'%'.$font_end.' '.$value;
}
} // end foreach $value => $count
// initialize stat(istics) row for this field, if required
if (!isset($table->stat[$row])) {
$table->stat[$row] = array(get_string($field, 'hotpot'));
}
// sort the values by frequency (using user-defined function)
usort($values, "hotpot_sort_stat_values");
// add stat(istics) values for this field
$table->stat[$row++][$col+1] = count($values) ? implode($br, $values) : $space;
}
} // end foreach field
// default percent correct and discrimination index for this question
$average = $no_value;
$percent = $no_value;
$d_index = $no_value;
if (isset($q[$id]['count'])) {
// average and percent correct
if ($q[$id]['count']['total']) {
$average = round($q[$id]['count']['sum'] / $q[$id]['count']['total']).'%';
$percent = round(100*$q[$id]['count']['correct'] / $q[$id]['count']['total']).'%';
$percent .= ' ('.$q[$id]['count']['correct'].'/'.$q[$id]['count']['total'].')';
}
// discrimination index
if ($q[$id]['count']['lo']) {
$d_index = min($max_d_index, round($q[$id]['count']['hi'] / $q[$id]['count']['lo'], 1));
} else {
$d_index = $q[$id]['count']['hi'] ? $max_d_index : 0;
}
$d_index .= ' ('.$q[$id]['count']['hi'].'/'.$q[$id]['count']['lo'].')';
}
$table->foot[0][$col+1] = $average;
$table->foot[1][$col+1] = $percent;
$table->foot[2][$col+1] = $d_index;
} // end foreach $question ($col)
// add javascript to show/hide question text
if (isset($table->stat[0]) && $is_html && empty($table->legend)) {
$i = count($table->stat[0]);
$table->stat[0][$i-1] .= hotpot_showhide_set($showhideid);
}
$tables[] = &$table;
$this->create_legend_table($tables, $table);
} // end if (empty($q)
} // end function
} // end class
function hotpot_sort_stat_values($a, $b) {
// sorts in descending order
// assumes first chars in $a and $b are a percentage
$a_val = intval(strip_tags($a));
$b_val = intval(strip_tags($b));
return ($a_val<$b_val) ? 1 : ($a_val==$b_val ? 0 : -1);
}
function hotpot_showhide_button($id) {
$show = get_string('show');
$hide = get_string('hide');
$pref = '1';
$text = ($pref=='1' ? $hide : $show);
return <<
//';
html += '';
html += '';
html += '';
document.writeln(html);
}
//]]>
SHOWHIDE_BUTTON
;
}
function hotpot_showhide_set($id) {
return <<
//
SHOWHIDE_SET
;
}
?>