Add-ons
  1. Add-ons
  2. CONTRIB-1715

Mean and standard deviation calculation (5 point scale)

    Details

    • Type: New Feature New Feature
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Won't Fix
    • Affects Version/s: 1.9.5
    • Fix Version/s: None
    • Component/s: Module: Questionnaire
    • Labels:
      None
    • Affected Branches:
      MOODLE_19_STABLE
    • Rank:
      21662

      Description

      Dear all,

      I have repackaged the questionnaire module as setlquestionnare to include the following features for our SETL (student evaluation of teaching):

      1) Adding a new response type "Rate (scale 1..100)" using a hard coded 5 point scale at (0, 25, 50, 75, 100). Using this option, the responses will be displayed with mean and standard deviation in the result table;
      2) Only the last response from a student will be used for calculation. This is to avoid a single student from submitting too many entries for affect the result); and
      3) This is a separate module on Moodle so that we can change the permission to allow only administrator to see the SETL result. Teacher can continue using the ordinary questionnaire module.

      I'm not sure if any other institutes may have similar requirement. Source code is attached below. Thanks.

      Regards,
      Murphy Wong

      1. questionnaire-setl.txt
        1.31 MB
        Murphy Wong
      2. setlquestionnaire_patch.txt
        706 kB
        Murphy Wong
      3. setlquestionnaire.tar.gz
        372 kB
        Murphy Wong
      4. setlquestionnaire.tar.gz
        615 kB
        Murphy Wong

        Activity

        Hide
        Mike Churchward added a comment -

        Can you provide diffs of the code you changed?

        Show
        Mike Churchward added a comment - Can you provide diffs of the code you changed?
        Hide
        Murphy Wong added a comment -

        Dear Mike,

        I've included a README_v3.txt file in the distribution. In fact, I have hacked 6 files:

        1) ~/db/install.xml
        Add question type 11, Rate (scale 1..100), for calculating mean and standard deviation for SETL (Student Evaluation of Teaching and Learning).
        2) ~/lib.php
        Disable function questionnaire_update_grades_original so that grades will not show in GradeBook
        3) ~/locallib.php
        Add total count for question type 11. Counting only the last record from a single user and ignore previous entries.
        4) ~/questions_form.php
        Add question type
        5) ~questiontypes/questiontypes.class.php
        Major hacked code in functions get_response_rank_results, display_results, display_response_rank_results, response_check_required, ratesd_survey_display, function ratesd_response_display, mkresavgsd, and insert_response_rank
        6) ~lang/en_utf8/questionnaire.php
        Update language file

        Afterwards, I did a global replacement of the 2 words "questionnaire" and "QUES" with "setlquestionnaire" and "SETL_QUES" respectively. Therefore, the "diff" of files will contain many lines of code. Anyway, I've included the "diff" of the 5 files below without the 2 global replacement differences:

        1) ~/db/install.xml
        238d237
        < <SENTENCE TEXT="(typeid, type, has_choices, response_table) VALUES (11,'Rate (scale 1..100)','y','response_rank')" />
        242c241
        < </XMLDB>

        > </XMLDB>

        2) ~/lib.php
        [root@centos5 setlquestionnaire]# diff lib.php.unix lib.php.ori
        296d295
        < // disabled by Murphy on November 27, 2009 so that grades will not show in GradeBook
        298,301d296
        < return NULL;
        < }
        <
        < function questionnaire_update_grades_original($questionnaire=null, $userid=0, $nullifnone=true) {
        723,724d717
        < case 11:
        < return get_string('ratescale_sd', 'questionnaire');
        891c884
        < ?>

        > ?>

        3) ~/locallib.php
        [root@centos5 setlquestionnaire]# diff locallib.php.unix locallib.php.ori
        1067,1069c1067
        < // Murphy Debug 20091006
        < // if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata->

        {'q'.$qid}) && $formdata->{'q'.$qid}

        == '') || (!isset($formdata->

        {'q'.$qid}))) && $tid != 8 && $tid != 100 ) {
        < if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata->{'q'.$qid}

        ) && $formdata->

        {'q'.$qid} == '') || (!isset($formdata->{'q'.$qid}

        ))) && $tid != 8 && $tid != 11 && $tid != 100 ) {

        > if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata->

        {'q'.$qid}) && $formdata->{'q'.$qid}

        == '') || (!isset($formdata->

        {'q'.$qid}))) && $tid != 8 && $tid != 100 ) {
        1161c1159
        < $checkdateresult = setl_check_date($formdata->{'q'.$qid}

        );

        > $checkdateresult = check_date($formdata->

        {'q'.$qid}

        );
        1176,1206d1173
        < case 11: // Rate SD
        < $num = 0;
        < $nbchoices = count($record->choices);
        < foreach ($record->choices as $cid => $choice) {
        < // in case we have named degrees on the Likert scale, count them to substract from nbchoices
        < $nameddegrees = 0;
        < $content = $choice->content;
        < if (ereg("^[0-9]

        {1,3}=", $content,$ndd)) { < $nameddegrees++; < } else {
        < $str = 'q'."{$record->id}_$cid";
        < for ($j = 0; $j < $record->length; $j++) { < $num += (isset($formdata->$str) && ($j == $formdata->$str)); < }
        < $num += (($record->precise) && isset($formdata->$str) && ($formdata->$str == -1));
        < }
        < $nbchoices -= $nameddegrees;
        < }
        < // echo "<P> Murphy DEBUG4: " . $strmissing;
        <
        < if ( $num == 0 && $record->required == 'y') { < $missing++; < $strmissing .= get_string('num', 'questionnaire').$qnum.'. '; < break; < }
        < if ( $num Unable to render embedded object: File (= $nbchoices && $num) not found.=0 ) { < $wrongformat++; < $strwrongformat .= get_string('num', 'questionnaire').$qnum.'. '; < }
        < break;
        <
        1407,1409c1374
        < // Murphy debug
        < // if ($qtype == 8) { // rate
        < if (($qtype == 8) || ($qtype == 11)) { // rate

        > if ($qtype == 8) { // rate
        1579c1544
        < $contents = setl_choice_values($value->content);

        > $contents = choice_values($value->content);
        1658c1623
        < $contents = setl_choice_values($c2);

        > $contents = choice_values($c2);
        1809c1774
        < $contents = setl_choice_values($contentleft);

        > $contents = choice_values($contentleft);
        1813c1778
        < $contents = setl_choice_values($contentright);

        > $contents = choice_values($contentright);
        1820c1785
        < $contents = setl_choice_values($val);

        > $contents = choice_values($val);
        2259,2260d2223
        <
        < // Murphy Debug total count
        2262,2274c2225
        < $sql = "SELECT COUNT(DISTINCT R.username) AS total
        < FROM ".$CFG->prefix."questionnaire_response R
        < WHERE R.survey_id='{$this->survey->id}'
        < AND R.complete='y'";
        < $records = get_records_sql($sql);
        < // print_r ($records[2]);
        < foreach ($records as $id => $record) { < // echo "MURPHY DEBUG: " . $record->total; < }
        <
        < // echo (' '.get_string('responses','questionnaire').": <strong>$total</strong>");
        < echo (' '.get_string('responses','questionnaire').": <strong>$total [ $record->total");
        < echo (' '.get_string('distinctrecord','questionnaire')." ]</strong>");

        > echo (' '.get_string('responses','questionnaire').": <strong>$total</strong>");
        2371d2321
        <
        2493c2443
        < $contents = setl_choice_values($content);

        > $contents = choice_values($content);
        2521c2471
        < $contents = setl_choice_values($contentleft);

        > $contents = choice_values($contentleft);
        2525c2475
        < $contents = setl_choice_values($contentright);

        > $contents = choice_values($contentright);
        2532c2482
        < $contents = setl_choice_values($content);

        > $contents = choice_values($content);
        2880c2830
        < function setl_check_date ($thisdate, $insert=false) {

        > function check_date ($thisdate, $insert=false) {
        3015c2965
        < function setl_choice_values($content) {

        > function choice_values($content) {
        3058c3008
        < ?>

        > ?>


        4) ~/questions_form.php
        [root@centos5 setlquestionnaire]# diff questions_form.php.unix questions_form.php.ori
        60,64d59
        <
        < // Murphy Debug
        < // echo "Murphy DEBUG";
        < // print_r($qtypes);
        <
        290,297d284
        < case QUESRATESD:
        < $deflength = 5;
        < $defprecise = 0;
        < $lhelpname = 'numberscaleitems';
        < $phelpname = 'kindofratescale';
        < $olabelname = 'possibleanswers';
        < $ohelpname = 'rateanswers';
        < break;
        439c426
        < ?>

        > ?>


        5) ~questiontypes/questiontypes.class.php
        [root@centos5 questiontypes]# diff questiontypes.class.php.unix questiontypes.class.php.ori
        30d29
        < define('QUESRATESD', 11);
        44d42
        < QUESRATESD => 'ratesd',
        258c256
        < $checkdateresult = setl_check_date($formdata->{'q'.$this->id});

        > $checkdateresult = check_date($formdata->{'q'.$this->id});
        264c262
        < $checkdateresult = setl_check_date($thisdate, $insert=true);

        > $checkdateresult = check_date($thisdate, $insert=true);
        365,367c363
        < // if($this->type_id == 8) { // Rank
        < // Murphy debug 20091005
        < if (($this->type_id == 8) || ($this->type_id == 11)) { // Rank

        > if($this->type_id == 8) { // Rank
        538,541c534
        < // Murphy Debug 20091006
        < // Major hacked for Rank SD (standard deviation) display
        < if ($this->type_id == 8) { //Rank
        < // if (($this->type_id == 8)||($this->type_id == 11)) { //Rank with SD

        > if($this->type_id == 8) { //Rank 558,583d550 < } else if ($this->type_id == 11) { //Rank with SD
        < $select = 'question_id='.$this->id.' AND content NOT LIKE \'!other%\'';
        < if ($rows = get_records_select('questionnaire_quest_choice', $select)) {
        < foreach ($rows as $row) { < $this->counts[$row->content] = null; < $nbna = count_records('questionnaire_response_rank', 'question_id', $this->id, 'choice_id', $row->id, 'rank', '-1'); < $this->counts[$row->content]->nbna = $nbna; < }
        < }
        < $sql = 'SELECT C.content, AVG(A.rank+1) AS average, '.
        < 'COUNT AS count, '.
        < /*
        < 'AVG(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(rank,1,75),0,100),2,50),3,25),4,0)) AS mean, '.
        < 'STDDEV(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(rank,1,75),0,100),2,50),3,25),4,0)) AS stddev '.
        < */
        < 'AVG(REPLACE(REPLACE(REPLACE(REPLACE(rank,2,50),1,25),3,75),4,100)) AS mean, '.
        < 'STDDEV(REPLACE(REPLACE(REPLACE(REPLACE(rank,2,50),1,25),3,75),4,100)) AS stddev '.
        < 'FROM '.$CFG->prefix.'questionnaire_quest_choice C, '.
        < $CFG->prefix.'questionnaire_'.$this->response_table.' A '.
        < 'WHERE C.question_id = '.$this->id.' AND A.question_id = '.$this->id.' AND '.
        < 'A.choice_id = C.id AND A.rank >= 0'.$ridstr.' '.
        < 'AND A.response_id IN (SELECT MAX(rid) FROM mdl_questionnaire_attempts GROUP BY userid, qid) '.
        < 'GROUP BY C.content';
        <
        < // echo "MURPHY DEBUG SQL: " . $sql;
        < return get_records_sql($sql);
        593d559
        <
        615,616c581
        < // Murphy Debug
        < // echo "Murphy Debug: " . $this->response_table;

        >
        695c660
        < $this->text = mktime(0, 0, 0, $dateparts[1], $dateparts[2], $dateparts[0]); // Unnix timestamp

        > $this->text = mktime(0, 0, 0, $dateparts[1], $dateparts[2], $dateparts[0]); // Unix timestamp
        722c687
        < $contents = setl_choice_values($row->content);

        > $contents = choice_values($row->content);
        751c716
        < $contents = setl_choice_values($row->content);

        > $contents = choice_values($row->content);
        770,771d734
        < // echo "MURPHY ";
        < // print_r($rids);
        773,775c736
        < // Murphy Debug 20091007
        < // Major hacked for Rank SD (standard deviation) display
        < if($this->type_id == 8) { //Rank

        > if($this->type_id == 8) { //Rank 782,793d742 < } else if ($this->type_id == 11) { //Rank
        < foreach ($rows as $row) { < $ccontent = $row->content; < $avg = $row->average; < $count = $row->count; < $mean = $row->mean; < $sd = $row->stddev; < $this->counts[$ccontent]->avg = $avg; < $this->counts[$ccontent]->mean = $mean; < $this->counts[$ccontent]->sd = $sd; < }
        < $this->mkresavgsd(count($rids), $this->precise, $prtotal, $this->length);
        873,875c822
        < // Murphy Debug 20091006
        < // if ($this->type_id == 8) { // Rate is a special case
        < if (($this->type_id == 8) || ($this->type_id == 11)) { // Rate is a special case

        > if ($this->type_id == 8) { // Rate is a special case
        1009c956
        < $contents = setl_choice_values($choice->content);

        > $contents = choice_values($choice->content);
        1147c1094
        < $contents = setl_choice_values($choice->content);

        > $contents = choice_values($choice->content);
        1182c1129
        < $content = setl_choice_values($choice->content)->text;

        > $content = choice_values($choice->content)->text;
        1223,1353c1170
        < $contents = setl_choice_values($content);
        < if ($contents->modname) { < $choice->content = $contents->text; < }
        < }
        < }
        < // if we have named degrees, provide for wider degree columns (than for numbers)
        < // do not provide wider degree columns if we have an Osgood's semantic differential
        < if ($nameddegrees && !$osgood) { < $colwidth = 'auto'; < } else { < $colwidth = '40px'; < }
        < for ($j = 0; $j < $this->length; $j++) {
        < if (isset($n[$j])) { < $str = $n[$j]; < } else { < $str = $j+1; < }
        < echo '<td style="width:'.$colwidth.'; text-align:center;" class="'.$bg.'">'.$str.'</td>';
        < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < }
        < }
        < if ($na) { < echo '<td style="width:'.$colwidth.'; text-align:center;" class="'.$bg.'">'.$na.'</td>'; < }
        < echo '</tr>';
        <
        < $num = 0;
        < $nbchoices = count($this->choices) - $nameddegrees;
        < foreach ($this->choices as $cid => $choice) {
        < $str = 'q'."{$this->id}_$cid";
        < for ($j = 0; $j < $this->length; $j++) { < $num += (isset($data->$str) && ($j == $data->$str)); < }
        < $num += (($na != '') && isset($data->$str) && ($data->$str == -1));
        < }
        < if ( ($num Unable to render embedded object: File (= $nbchoices) && ($num) not found.=0) ) { < questionnaire_notify(get_string('checkallradiobuttons', 'questionnaire', $nbchoices)); < }
        < $bgr = 'qntype r0';
        < foreach ($this->choices as $cid => $choice) {
        < if (isset($choice->content)) {
        < $str = 'q'."{$this->id}_$cid";
        < echo '<tr>';
        < $content = $choice->content;
        < if ($osgood) { < list($content, $contentright) = split('[|]', $content); < }
        < echo '<td class="'.$bgr.'">'.format_text($content, FORMAT_HTML).' </td>';
        < if ($bgr == 'qntype r0') { < $bgr = 'qntype r1'; < } else { < $bgr = 'qntype r0'; < }
        < $bg = 'qntype c0';
        < for ($j = 0; $j < $this->length; $j++) {
        < $checked = ((isset($data->$str) && ($j == $data->$str)) ? ' checked="checked"' : '');
        < echo '<td style="text-align:center" class="'.$bg.'">';
        < echo '<input name="'.$str.'" type="radio" value="'.$j.'"'.$checked.$order.' /></td>';
        < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < }
        < }
        < if ($na) {
        < if ( (in_array($na, $data->{'q'.$this->id})) ||
        < ((isset($data->$str) && ($data->$str == -1)) ) ) { < $checked = ' checked="checked"'; < } else { < $checked = ''; < }
        < echo '<td style="width:40; text-align:center" class="'.$bg.'">';
        < echo '<input name="'.$str.'" type="radio" value="'.$na.'"'.$checked.' /></td>';
        < }
        < if ($osgood) {
        < if ($bgr == 'qntype r0') { < $bgr2 = 'qntype r1'; < } else { < $bgr2 = 'qntype r0'; < }
        < echo '<td class="'.$bgr2.'"> '.format_text($contentright, FORMAT_HTML).'</td>';
        < }
        < echo '</tr>';
        < }
        < }
        < echo '</tbody>';
        < echo '</table>';
        < }
        <
        < // Murphy debug 20091005
        < function ratesd_survey_display($data) { // Rate_SD
        < if (!isset($data->{'q'.$this->id}) || !is_array($data->{'q'.$this->id})) {
        < $data->{'q'.$this->id} = array();
        < }
        < echo '<table border="0" cellspacing="1" cellpadding="0">';
        < echo '<tbody>';
        < echo '<tr>';
        < echo '<td></td>';
        < $bg = 'qntype c0';
        < if ($this->precise == 1) { < $na = get_string('notapplicable', 'questionnaire'); < } else { < $na = ''; < }
        < if ($this->precise == 2) { < $order = ' onclick="other_rate_uncheck(name, value)" '; < } else { < $order = ''; < }
        < $osgood = false;
        < if ($this->precise == 3) { // Osgood's semantic differential < $osgood = true; < }
        < $nameddegrees = 0;
        < $n = array();
        < $mods = array();
        < foreach ($this->choices as $cid => $choice) {
        < $content = $choice->content;
        < // check for number from 1 to 3 digits, followed by the equal sign = (to accomodate named degrees)
        < if (ereg("^([0-9]{1,3}

        )=(.*)$", $content,$ndd))

        { < $n[$nameddegrees] = format_text($ndd[2], FORMAT_HTML); < $this->choices[$cid] = ''; < $nameddegrees++; < }

        < else {
        < $contents = setl_choice_values($content);

        > $contents = choice_values($content);
        1452c1269
        < $setdate = setl_check_date ($dateentered, false);

        > $setdate = check_date ($dateentered, false);
        1587c1404
        < $contents = setl_choice_values($choice->content);

        > $contents = choice_values($choice->content);
        1632c1449
        < $contents = setl_choice_values($choice->content);

        > $contents = choice_values($choice->content);
        1673c1490
        < $content = setl_choice_values($choice->content)->text;

        > $content = choice_values($choice->content)->text;
        1739,1844c1556
        < $contents = setl_choice_values($content);
        < if ($contents->modname)

        { < $content = $contents->text; < }

        < if ($osgood)

        { < list($content, $contentright) = split('[|]', $content); < }

        < echo '<td align="left">'.format_text($content, FORMAT_HTML).' </td>';
        < $bg = 'qntype c0';
        < for ($j = 0; $j < $this->length; $j++) {
        < $checked = ((isset($data->$str) && ($j == $data->$str)) ? ' checked="checked"' : '');
        < $checkedna = ((isset($data->$str) && ($data->$str == -1)) ? ' checked="checked"' : ''); // N/A column checked
        < echo '<td style="width:40; text-align:center;" class="'.$bg.'">';
        < if ($checked)

        { < echo '<span class="selected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'" checked="checked" /></span>'; < }

        else

        { < echo '<span class="unselected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'" onclick="this.checked=false;" /></span>'; < }

        < echo '</td>';
        < if ($bg == 'qntype c0')

        { < $bg = 'qntype c1'; < }

        else

        { < $bg = 'qntype c0'; < }

        < }
        < if ($this->precise == 1) { // N/A column
        < echo '<td style="width:40; text-align:center;" class="'.$bg.'">';
        < if ($checkedna)

        { < echo '<span class="selected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'na" checked="checked" /></span>'; < }

        else

        { < echo '<span class="unselected">'. < '<input type="radio" name="'.$str.$uniquetag++.'na" onclick="this.checked=false;" /></span>'; < }

        < echo '</td>';
        < }
        < if ($osgood)

        { < echo '<td> '.format_text($contentright, FORMAT_HTML).'</td>'; < }

        <
        < echo '</tr>';
        < }
        < }
        < echo '</tbody></table></div>';
        < }
        <
        < // Murphy debug 20091005
        < function ratesd_response_display($data) {
        < static $uniquetag = 0; // To make sure all radios have unique names.
        <
        < if (!isset($data->

        {'q'.$this->id}) || !is_array($data->{'q'.$this->id}

        )) {
        < $data->

        {'q'.$this->id}

        = array();
        < }
        <
        < echo '<div class="response rate">';
        < echo '<table border="0" cellspacing="1" cellpadding="0">';
        < echo '<tbody><tr><td></td>';
        < $bg = 'qntype c0';
        < $osgood = false;
        < if ($this->precise == 3)

        { // Osgood's semantic differential < $osgood = true; < }
        < $nameddegrees = 0;
        < $cidnamed = array();
        < $n = array();
        < foreach ($this->choices as $cid => $choice) {
        < $content = $choice->content;
        < if (ereg("^[0-9]{1,3}=", $content,$ndd)) { < $n[$nameddegrees] = format_text(substr($content, strlen($ndd[0])), FORMAT_HTML); < $cidnamed[$cid] = true; < $nameddegrees++; < }
        < }
        < if ($nameddegrees && !$osgood) { < $colwidth = 80; < } else { < $colwidth = 40; < }
        <
        < for ($j = 0; $j < $this->length; $j++) {
        < if (isset($n[$j])) { < $str = $n[$j]; < } else { < $str = $j+1; < }
        < echo '<td style="width:'.$colwidth.'; text-align:center" class="'.$bg.'">'.$str.'</td>';
        < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < }
        < }
        < if ($this->precise == 1) { < echo '<td style="width:'.$colwidth.'; text-align:center" class="'.$bg.'">'.get_string('notapplicable', 'questionnaire').'</td>'; < }
        < echo '</tr>';
        <
        < foreach ($this->choices as $cid => $choice) {
        < // do not print column names if named column exist
        < if (!array_key_exists($cid, $cidnamed)) {
        < $str = 'q'."{$this->id}_$cid";
        < echo '<tr>';
        < $content = $choice->content;
        < $contents = setl_choice_values($content);

        > $contents = choice_values($content);
        2205c1917
        < $contents = setl_choice_values($content);

        > $contents = choice_values($content);
        2232,2365d1943
        <
        < // Murphy Debug 20091007
        < // Major hacked for Rank SD (standard deviation) display
        < function mkresavgsd($total, $precision, $showTotals, $length) {
        < global $CFG;
        <
        < $stravg = '<div style="text-align:center">'.get_string('averagerank', 'questionnaire').'</div>';
        < $isna = $this->precise == 1;
        < $isnahead = '';
        < $osgood = false;
        < if ($precision == 3) { // Osgood's semantic differential < $osgood = true; < }

        <
        < if ($isna)

        { < $isnahead = get_string('notapplicable', 'questionnaire').'<br />(#)'; < }

        < $table = new Object();
        <
        < $table->align = array('', 'left', 'right', 'center');
        < if ($isna)

        { < $table->head = array('', $stravg, '',$isnahead); < }

        else {
        < if ($osgood)

        { < $table->head = array('', $stravg, '', ''); < }

        else

        { < // $table->head = array('', $stravg, ''); < $table->head = array('', $stravg, get_string('mean', 'questionnaire'), get_string('standarddeviation', 'questionnaire')); < }

        < }
        < if (!$osgood)

        { < $rightcolwidth = '5%'; < }

        else

        { < $rightcolwidth = '25%'; < }

        < $table->size = array('*', '40%', $rightcolwidth,'5%');
        <
        < $image_url = $CFG->wwwroot.'/mod/questionnaire/images/';
        < $currhbar = $this->theme_bars_url();
        <
        < if (!$length)

        { < $length = 5; < }

        < $nacol = 0;
        < $width = 100 / $length ;
        < $n = array();
        < $nameddegrees = 0;
        < foreach ($this->choices as $choice) {
        < // to take into account languages filter
        < $content = (format_text($choice->content, FORMAT_HTML));
        < if (ereg("^[0-9]

        {1,3}=", $content,$ndd)) { < $n[$nameddegrees] = substr($content, strlen($ndd[0])); < $nameddegrees++; < }
        < }
        < $align = 'center';
        < for ($j = 0; $j < $this->length; $j++) {
        < if (isset($n[$j])) { < $str = $n[$j]; < } else { < $str = $j+1; < }
        < }
        < $out = '<table style="width:100%" cellpadding="2" cellspacing="0" border="1"><tr>';
        < for ($i = 0; $i <= $length - 1; $i++) {
        < if (isset($n[$i])) { < $str = $n[$i]; < } else { < $str = $i + 1; < }
        < $out .= '<td align = "center" style="width:'.$width.'%" >'.$str.'</td>';
        < }
        < $out .= '</tr></table>';
        < // $table->data[] = array('', $out, '');
        < $table->data[] = array('', $out, '', '');
        <
        < if (!empty($this->counts) && is_array($this->counts)) {
        < while(list($content) = each($this->counts)) {
        <
        < // eliminate potential named degrees on Likert scale
        < if (!ereg("^[0-9]{1,3}

        =", $content)) {
        < if (isset($this->counts[$content]->avg))

        { < $avg = $this->counts[$content]->avg; < $mean = $this->counts[$content]->mean; < $sd = $this->counts[$content]->sd; < }

        else

        { < $avg = ''; < $mean = ''; < $sd = ''; < }

        < $nbna = $this->counts[$content]->nbna;
        <
        < if($avg) {
        < $out = '';
        < if (($j = $avg * $width) > 0)

        { < $interval = 50 / $length; < $out .= sprintf('<img alt="" src="'.$image_url.$currhbar. < 'rhbar.gif" height="0" width="%d%%" style="visibility:hidden" />', $j - $interval - 0.3); < }

        < $out .= '<img alt="" src="'.$image_url.$currhbar.'rhbar.gif" height="12" width="6" />';
        < } else

        { < $out = ''; < }

        <
        < $contents = setl_choice_values($content);
        < if ($contents->modname)

        { < $content = $contents->text; < }

        < if ($osgood)

        { < list($content, $contentright) = split('[|]', $content); < }


        < if (!$isna) {
        < if ($osgood)

        { < // $table->data[] = array('<div align="right">'.format_text($content, FORMAT_HTML).'</div>', $out, '<div align="left"><strong>'.format_text($contentright, FORMAT_HTML).'</strong></div>', sprintf('%.1f', $avg)); < $table->data[] = array('<div align="right">'.format_text($content, FORMAT_HTML).'</div>', $out, '<div align="left"><strong>'.format_text($contentright, FORMAT_HTML).'</strong></div>', sprintf('%.1f', $mean), sprintf('(%.1f)', $sd)); < }

        else

        { < // $table->data[] = array(format_text($content, FORMAT_HTML), $out, sprintf('%.1f', $avg)); < $table->data[] = array(format_text($content, FORMAT_HTML), $out, sprintf('%.1f', $mean), sprintf('(%.1f)', $sd)); < }

        < } else {
        < if ($avg)

        { < $avg = sprintf('%.1f', $avg); < }

        < $table->data[] = array(format_text($content, FORMAT_HTML), $out, $avg, $nbna);
        < }
        < } // end if named degrees
        < } // end while
        < } else

        { < $table->data[] = array('', get_string('noresponsedata', 'questionnaire')); < }

        < print_table($table);
        < }
        <
        <

        6) ~lang/en_utf8/questionnaire.php
        [root@centos5 en_utf8]# diff setlquestionnaire.php.unix questionnaire.php.ori
        1c1
        < <?php // $Id: setlquestionnaire.php,v 1.10.2.16 2009/03/17 14:18:51 joseph_rezeau Exp $

        > <?php // $Id: questionnaire.php,v 1.10.2.16 2009/03/17 14:18:51 joseph_rezeau Exp $
        44d43
        < $string['distinctrecord'] = 'distinct record(s)';
        76d74
        < $string['mean'] = 'Mean';
        81,84c79,80
        <
        < $string['modulename'] = 'SETL Questionnaire';
        < $string['modulenameplural'] = 'SETL Questionnaires';
        <

        > $string['modulename'] = 'Questionnaire';
        > $string['modulenameplural'] = 'Questionnaires';
        172d167
        < $string['ratescale_sd'] = 'Rate (scale 1..100)';
        211,230d205
        <
        < $string['setlquestionnaire'] = 'SETL Questionnaire';
        < $string['setlquestionnaire:copysurveys'] = 'Copy template and private questionnaires';
        < $string['setlquestionnaire:createpublic'] = 'Create public questionnaires';
        < $string['setlquestionnaire:createtemplates'] = 'Create template questionnaires';
        < $string['setlquestionnaire:deleteresponses'] = 'Delete any response';
        < $string['setlquestionnaire:downloadresponses'] = 'Download responses in a CSV file';
        < $string['setlquestionnaire:editquestions'] = 'Create and edit questionnaire questions';
        < $string['setlquestionnaire:manage'] = 'Create and edit questionnaires';
        < $string['setlquestionnaire:printblank'] = 'Print blank questionnaire';
        < $string['setlquestionnaire:readallresponseanytime'] = 'Read all responses any time';
        < $string['setlquestionnaire:readallresponses'] = 'Read response summaries, subject to open times';
        < $string['setlquestionnaire:readownresponses'] = 'Read own responses';
        < $string['setlquestionnaire:submit'] = 'Complete and submit a questionnaire';
        < $string['setlquestionnaire:view'] = 'View a questionnaire';
        < $string['setlquestionnaire:viewsingleresponse'] = 'View complete individual responses';
        < $string['setlquestionnairecloses'] = 'Questionnaire Closes';
        < $string['setlquestionnaireopens'] = 'Questionnaire Opens';
        < $string['setlquestionnairereport'] = 'Questionnaire Report';
        <
        233d207
        < $string['standarddeviation'] = 'Standard deviation';
        276d249
        <

        Actually, my colleague prefer repackage the module as a new one so that the original questionnaire module can leave unchanged. This SETL can only be used by the course administrator for asking the questions about the course & teacher's performance. It is sensitive to teacher and therefore we restrict teacher's access to this setlquestionnaire module. Thanks.

        Regards,
        Murphy

        Mr. Murphy C.K. Wong
        Senior IT Manager
        Centre for Information Technology in Education (CITE), Faculty of Education, HKU
        Office: Rm 110, Runme Shaw Bldg, CITE, HKU
        Tel: (852)-2241-5669, Fax: (852)-2517-7194

        ----Original Message----
        From: Mike Churchward (Moodle Tracker) contrib@moodle.org
        Sent: Saturday, January 09, 2010 4:28 AM
        To: murphy.wong@hku.hk
        Subject: [Moodle] Commented: (CONTRIB-1715) Mean and standard deviation calculation (5 point scale)

        [ http://tracker.moodle.org/browse/CONTRIB-1715?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=79550#action_79550 ]

        Mike Churchward commented on CONTRIB-1715:
        ------------------------------------------

        Can you provide diffs of the code you changed?

        > Mean and standard deviation calculation (5 point scale)
        > -------------------------------------------------------
        >
        > Key: CONTRIB-1715
        > URL: http://tracker.moodle.org/browse/CONTRIB-1715
        > Project: Non-core contributed modules
        > Issue Type: New Feature
        > Components: Module: Questionnaire
        > Affects Versions: 1.9.5
        > Reporter: Murphy Wong
        > Assignee: Mike Churchward
        > Attachments: setlquestionnaire.tar.gz
        >
        >
        > Dear all,
        > I have repackaged the questionnaire module as setlquestionnare to include the following features for our SETL (student evaluation of teaching):
        > 1) Adding a new response type "Rate (scale 1..100)" using a hard coded 5 point scale at (0, 25, 50, 75, 100). Using this option, the responses will be displayed with mean and standard deviation in the result table;
        > 2) Only the last response from a student will be used for calculation. This is to avoid a single student from submitting too many entries for affect the result); and
        > 3) This is a separate module on Moodle so that we can change the permission to allow only administrator to see the SETL result. Teacher can continue using the ordinary questionnaire module.
        > I'm not sure if any other institutes may have similar requirement. Source code is attached below. Thanks.
        > Regards,
        > Murphy Wong

        Show
        Murphy Wong added a comment - Dear Mike, I've included a README_v3.txt file in the distribution. In fact, I have hacked 6 files: 1) ~/db/install.xml Add question type 11, Rate (scale 1..100), for calculating mean and standard deviation for SETL (Student Evaluation of Teaching and Learning). 2) ~/lib.php Disable function questionnaire_update_grades_original so that grades will not show in GradeBook 3) ~/locallib.php Add total count for question type 11. Counting only the last record from a single user and ignore previous entries. 4) ~/questions_form.php Add question type 5) ~questiontypes/questiontypes.class.php Major hacked code in functions get_response_rank_results, display_results, display_response_rank_results, response_check_required, ratesd_survey_display, function ratesd_response_display, mkresavgsd, and insert_response_rank 6) ~lang/en_utf8/questionnaire.php Update language file Afterwards, I did a global replacement of the 2 words "questionnaire" and "QUES" with "setlquestionnaire" and "SETL_QUES" respectively. Therefore, the "diff" of files will contain many lines of code. Anyway, I've included the "diff" of the 5 files below without the 2 global replacement differences: 1) ~/db/install.xml 238d237 < <SENTENCE TEXT="(typeid, type, has_choices, response_table) VALUES (11,'Rate (scale 1..100)','y','response_rank')" /> 242c241 < </XMLDB> — > </XMLDB> 2) ~/lib.php [root@centos5 setlquestionnaire] # diff lib.php.unix lib.php.ori 296d295 < // disabled by Murphy on November 27, 2009 so that grades will not show in GradeBook 298,301d296 < return NULL; < } < < function questionnaire_update_grades_original($questionnaire=null, $userid=0, $nullifnone=true) { 723,724d717 < case 11: < return get_string('ratescale_sd', 'questionnaire'); 891c884 < ?> — > ?> 3) ~/locallib.php [root@centos5 setlquestionnaire] # diff locallib.php.unix locallib.php.ori 1067,1069c1067 < // Murphy Debug 20091006 < // if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata-> {'q'.$qid}) && $formdata->{'q'.$qid} == '') || (!isset($formdata-> {'q'.$qid}))) && $tid != 8 && $tid != 100 ) { < if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata->{'q'.$qid} ) && $formdata-> {'q'.$qid} == '') || (!isset($formdata->{'q'.$qid} ))) && $tid != 8 && $tid != 11 && $tid != 100 ) { — > if ( ($record->required == 'y') && ($record->deleted == 'n') && ((isset($formdata-> {'q'.$qid}) && $formdata->{'q'.$qid} == '') || (!isset($formdata-> {'q'.$qid}))) && $tid != 8 && $tid != 100 ) { 1161c1159 < $checkdateresult = setl_check_date($formdata->{'q'.$qid} ); — > $checkdateresult = check_date($formdata-> {'q'.$qid} ); 1176,1206d1173 < case 11: // Rate SD < $num = 0; < $nbchoices = count($record->choices); < foreach ($record->choices as $cid => $choice) { < // in case we have named degrees on the Likert scale, count them to substract from nbchoices < $nameddegrees = 0; < $content = $choice->content; < if (ereg("^ [0-9] {1,3}=", $content,$ndd)) { < $nameddegrees++; < } else { < $str = 'q'."{$record->id}_$cid"; < for ($j = 0; $j < $record->length; $j++) { < $num += (isset($formdata->$str) && ($j == $formdata->$str)); < } < $num += (($record->precise) && isset($formdata->$str) && ($formdata->$str == -1)); < } < $nbchoices -= $nameddegrees; < } < // echo "<P> Murphy DEBUG4: " . $strmissing; < < if ( $num == 0 && $record->required == 'y') { < $missing++; < $strmissing .= get_string('num', 'questionnaire').$qnum.'. '; < break; < } < if ( $num Unable to render embedded object: File (= $nbchoices && $num) not found. =0 ) { < $wrongformat++; < $strwrongformat .= get_string('num', 'questionnaire').$qnum.'. '; < } < break; < 1407,1409c1374 < // Murphy debug < // if ($qtype == 8) { // rate < if (($qtype == 8) || ($qtype == 11)) { // rate — > if ($qtype == 8) { // rate 1579c1544 < $contents = setl_choice_values($value->content); — > $contents = choice_values($value->content); 1658c1623 < $contents = setl_choice_values($c2); — > $contents = choice_values($c2); 1809c1774 < $contents = setl_choice_values($contentleft); — > $contents = choice_values($contentleft); 1813c1778 < $contents = setl_choice_values($contentright); — > $contents = choice_values($contentright); 1820c1785 < $contents = setl_choice_values($val); — > $contents = choice_values($val); 2259,2260d2223 < < // Murphy Debug total count 2262,2274c2225 < $sql = "SELECT COUNT(DISTINCT R.username) AS total < FROM ".$CFG->prefix."questionnaire_response R < WHERE R.survey_id='{$this->survey->id}' < AND R.complete='y'"; < $records = get_records_sql($sql); < // print_r ($records [2] ); < foreach ($records as $id => $record) { < // echo "MURPHY DEBUG: " . $record->total; < } < < // echo (' '.get_string('responses','questionnaire').": <strong>$total</strong>"); < echo (' '.get_string('responses','questionnaire').": <strong>$total [ $record->total"); < echo (' '.get_string('distinctrecord','questionnaire')." ]</strong>"); — > echo (' '.get_string('responses','questionnaire').": <strong>$total</strong>"); 2371d2321 < 2493c2443 < $contents = setl_choice_values($content); — > $contents = choice_values($content); 2521c2471 < $contents = setl_choice_values($contentleft); — > $contents = choice_values($contentleft); 2525c2475 < $contents = setl_choice_values($contentright); — > $contents = choice_values($contentright); 2532c2482 < $contents = setl_choice_values($content); — > $contents = choice_values($content); 2880c2830 < function setl_check_date ($thisdate, $insert=false) { — > function check_date ($thisdate, $insert=false) { 3015c2965 < function setl_choice_values($content) { — > function choice_values($content) { 3058c3008 < ?> — > ?> 4) ~/questions_form.php [root@centos5 setlquestionnaire] # diff questions_form.php.unix questions_form.php.ori 60,64d59 < < // Murphy Debug < // echo "Murphy DEBUG"; < // print_r($qtypes); < 290,297d284 < case QUESRATESD: < $deflength = 5; < $defprecise = 0; < $lhelpname = 'numberscaleitems'; < $phelpname = 'kindofratescale'; < $olabelname = 'possibleanswers'; < $ohelpname = 'rateanswers'; < break; 439c426 < ?> — > ?> 5) ~questiontypes/questiontypes.class.php [root@centos5 questiontypes] # diff questiontypes.class.php.unix questiontypes.class.php.ori 30d29 < define('QUESRATESD', 11); 44d42 < QUESRATESD => 'ratesd', 258c256 < $checkdateresult = setl_check_date($formdata->{'q'.$this->id}); — > $checkdateresult = check_date($formdata->{'q'.$this->id}); 264c262 < $checkdateresult = setl_check_date($thisdate, $insert=true); — > $checkdateresult = check_date($thisdate, $insert=true); 365,367c363 < // if($this->type_id == 8) { // Rank < // Murphy debug 20091005 < if (($this->type_id == 8) || ($this->type_id == 11)) { // Rank — > if($this->type_id == 8) { // Rank 538,541c534 < // Murphy Debug 20091006 < // Major hacked for Rank SD (standard deviation) display < if ($this->type_id == 8) { //Rank < // if (($this->type_id == 8)||($this->type_id == 11)) { //Rank with SD — > if($this->type_id == 8) { //Rank 558,583d550 < } else if ($this->type_id == 11) { //Rank with SD < $select = 'question_id='.$this->id.' AND content NOT LIKE \'!other%\''; < if ($rows = get_records_select('questionnaire_quest_choice', $select)) { < foreach ($rows as $row) { < $this->counts[$row->content] = null; < $nbna = count_records('questionnaire_response_rank', 'question_id', $this->id, 'choice_id', $row->id, 'rank', '-1'); < $this->counts[$row->content]->nbna = $nbna; < } < } < $sql = 'SELECT C.content, AVG(A.rank+1) AS average, '. < 'COUNT AS count, '. < /* < 'AVG(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(rank,1,75),0,100),2,50),3,25),4,0)) AS mean, '. < 'STDDEV(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(rank,1,75),0,100),2,50),3,25),4,0)) AS stddev '. < */ < 'AVG(REPLACE(REPLACE(REPLACE(REPLACE(rank,2,50),1,25),3,75),4,100)) AS mean, '. < 'STDDEV(REPLACE(REPLACE(REPLACE(REPLACE(rank,2,50),1,25),3,75),4,100)) AS stddev '. < 'FROM '.$CFG->prefix.'questionnaire_quest_choice C, '. < $CFG->prefix.'questionnaire_'.$this->response_table.' A '. < 'WHERE C.question_id = '.$this->id.' AND A.question_id = '.$this->id.' AND '. < 'A.choice_id = C.id AND A.rank >= 0'.$ridstr.' '. < 'AND A.response_id IN (SELECT MAX(rid) FROM mdl_questionnaire_attempts GROUP BY userid, qid) '. < 'GROUP BY C.content'; < < // echo "MURPHY DEBUG SQL: " . $sql; < return get_records_sql($sql); 593d559 < 615,616c581 < // Murphy Debug < // echo "Murphy Debug: " . $this->response_table; — > 695c660 < $this->text = mktime(0, 0, 0, $dateparts [1] , $dateparts [2] , $dateparts [0] ); // Unnix timestamp — > $this->text = mktime(0, 0, 0, $dateparts [1] , $dateparts [2] , $dateparts [0] ); // Unix timestamp 722c687 < $contents = setl_choice_values($row->content); — > $contents = choice_values($row->content); 751c716 < $contents = setl_choice_values($row->content); — > $contents = choice_values($row->content); 770,771d734 < // echo "MURPHY "; < // print_r($rids); 773,775c736 < // Murphy Debug 20091007 < // Major hacked for Rank SD (standard deviation) display < if($this->type_id == 8) { //Rank — > if($this->type_id == 8) { //Rank 782,793d742 < } else if ($this->type_id == 11) { //Rank < foreach ($rows as $row) { < $ccontent = $row->content; < $avg = $row->average; < $count = $row->count; < $mean = $row->mean; < $sd = $row->stddev; < $this->counts[$ccontent]->avg = $avg; < $this->counts[$ccontent]->mean = $mean; < $this->counts[$ccontent]->sd = $sd; < } < $this->mkresavgsd(count($rids), $this->precise, $prtotal, $this->length); 873,875c822 < // Murphy Debug 20091006 < // if ($this->type_id == 8) { // Rate is a special case < if (($this->type_id == 8) || ($this->type_id == 11)) { // Rate is a special case — > if ($this->type_id == 8) { // Rate is a special case 1009c956 < $contents = setl_choice_values($choice->content); — > $contents = choice_values($choice->content); 1147c1094 < $contents = setl_choice_values($choice->content); — > $contents = choice_values($choice->content); 1182c1129 < $content = setl_choice_values($choice->content)->text; — > $content = choice_values($choice->content)->text; 1223,1353c1170 < $contents = setl_choice_values($content); < if ($contents->modname) { < $choice->content = $contents->text; < } < } < } < // if we have named degrees, provide for wider degree columns (than for numbers) < // do not provide wider degree columns if we have an Osgood's semantic differential < if ($nameddegrees && !$osgood) { < $colwidth = 'auto'; < } else { < $colwidth = '40px'; < } < for ($j = 0; $j < $this->length; $j++) { < if (isset($n [$j] )) { < $str = $n[$j]; < } else { < $str = $j+1; < } < echo '<td style="width:'.$colwidth.'; text-align:center;" class="'.$bg.'">'.$str.'</td>'; < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < } < } < if ($na) { < echo '<td style="width:'.$colwidth.'; text-align:center;" class="'.$bg.'">'.$na.'</td>'; < } < echo '</tr>'; < < $num = 0; < $nbchoices = count($this->choices) - $nameddegrees; < foreach ($this->choices as $cid => $choice) { < $str = 'q'."{$this->id}_$cid"; < for ($j = 0; $j < $this->length; $j++) { < $num += (isset($data->$str) && ($j == $data->$str)); < } < $num += (($na != '') && isset($data->$str) && ($data->$str == -1)); < } < if ( ($num Unable to render embedded object: File (= $nbchoices) && ($num) not found. =0) ) { < questionnaire_notify(get_string('checkallradiobuttons', 'questionnaire', $nbchoices)); < } < $bgr = 'qntype r0'; < foreach ($this->choices as $cid => $choice) { < if (isset($choice->content)) { < $str = 'q'."{$this->id}_$cid"; < echo '<tr>'; < $content = $choice->content; < if ($osgood) { < list($content, $contentright) = split('[|]', $content); < } < echo '<td class="'.$bgr.'">'.format_text($content, FORMAT_HTML).' </td>'; < if ($bgr == 'qntype r0') { < $bgr = 'qntype r1'; < } else { < $bgr = 'qntype r0'; < } < $bg = 'qntype c0'; < for ($j = 0; $j < $this->length; $j++) { < $checked = ((isset($data->$str) && ($j == $data->$str)) ? ' checked="checked"' : ''); < echo '<td style="text-align:center" class="'.$bg.'">'; < echo '<input name="'.$str.'" type="radio" value="'.$j.'"'.$checked.$order.' /></td>'; < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < } < } < if ($na) { < if ( (in_array($na, $data->{'q'.$this->id})) || < ((isset($data->$str) && ($data->$str == -1)) ) ) { < $checked = ' checked="checked"'; < } else { < $checked = ''; < } < echo '<td style="width:40; text-align:center" class="'.$bg.'">'; < echo '<input name="'.$str.'" type="radio" value="'.$na.'"'.$checked.' /></td>'; < } < if ($osgood) { < if ($bgr == 'qntype r0') { < $bgr2 = 'qntype r1'; < } else { < $bgr2 = 'qntype r0'; < } < echo '<td class="'.$bgr2.'"> '.format_text($contentright, FORMAT_HTML).'</td>'; < } < echo '</tr>'; < } < } < echo '</tbody>'; < echo '</table>'; < } < < // Murphy debug 20091005 < function ratesd_survey_display($data) { // Rate_SD < if (!isset($data->{'q'.$this->id}) || !is_array($data->{'q'.$this->id})) { < $data->{'q'.$this->id} = array(); < } < echo '<table border="0" cellspacing="1" cellpadding="0">'; < echo '<tbody>'; < echo '<tr>'; < echo '<td></td>'; < $bg = 'qntype c0'; < if ($this->precise == 1) { < $na = get_string('notapplicable', 'questionnaire'); < } else { < $na = ''; < } < if ($this->precise == 2) { < $order = ' onclick="other_rate_uncheck(name, value)" '; < } else { < $order = ''; < } < $osgood = false; < if ($this->precise == 3) { // Osgood's semantic differential < $osgood = true; < } < $nameddegrees = 0; < $n = array(); < $mods = array(); < foreach ($this->choices as $cid => $choice) { < $content = $choice->content; < // check for number from 1 to 3 digits, followed by the equal sign = (to accomodate named degrees) < if (ereg("^( [0-9] {1,3} )=(.*)$", $content,$ndd)) { < $n[$nameddegrees] = format_text($ndd[2], FORMAT_HTML); < $this->choices[$cid] = ''; < $nameddegrees++; < } < else { < $contents = setl_choice_values($content); — > $contents = choice_values($content); 1452c1269 < $setdate = setl_check_date ($dateentered, false); — > $setdate = check_date ($dateentered, false); 1587c1404 < $contents = setl_choice_values($choice->content); — > $contents = choice_values($choice->content); 1632c1449 < $contents = setl_choice_values($choice->content); — > $contents = choice_values($choice->content); 1673c1490 < $content = setl_choice_values($choice->content)->text; — > $content = choice_values($choice->content)->text; 1739,1844c1556 < $contents = setl_choice_values($content); < if ($contents->modname) { < $content = $contents->text; < } < if ($osgood) { < list($content, $contentright) = split('[|]', $content); < } < echo '<td align="left">'.format_text($content, FORMAT_HTML).' </td>'; < $bg = 'qntype c0'; < for ($j = 0; $j < $this->length; $j++) { < $checked = ((isset($data->$str) && ($j == $data->$str)) ? ' checked="checked"' : ''); < $checkedna = ((isset($data->$str) && ($data->$str == -1)) ? ' checked="checked"' : ''); // N/A column checked < echo '<td style="width:40; text-align:center;" class="'.$bg.'">'; < if ($checked) { < echo '<span class="selected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'" checked="checked" /></span>'; < } else { < echo '<span class="unselected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'" onclick="this.checked=false;" /></span>'; < } < echo '</td>'; < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < } < } < if ($this->precise == 1) { // N/A column < echo '<td style="width:40; text-align:center;" class="'.$bg.'">'; < if ($checkedna) { < echo '<span class="selected">'. < '<input type="radio" name="'.$str.$j.$uniquetag++.'na" checked="checked" /></span>'; < } else { < echo '<span class="unselected">'. < '<input type="radio" name="'.$str.$uniquetag++.'na" onclick="this.checked=false;" /></span>'; < } < echo '</td>'; < } < if ($osgood) { < echo '<td> '.format_text($contentright, FORMAT_HTML).'</td>'; < } < < echo '</tr>'; < } < } < echo '</tbody></table></div>'; < } < < // Murphy debug 20091005 < function ratesd_response_display($data) { < static $uniquetag = 0; // To make sure all radios have unique names. < < if (!isset($data-> {'q'.$this->id}) || !is_array($data->{'q'.$this->id} )) { < $data-> {'q'.$this->id} = array(); < } < < echo '<div class="response rate">'; < echo '<table border="0" cellspacing="1" cellpadding="0">'; < echo '<tbody><tr><td></td>'; < $bg = 'qntype c0'; < $osgood = false; < if ($this->precise == 3) { // Osgood's semantic differential < $osgood = true; < } < $nameddegrees = 0; < $cidnamed = array(); < $n = array(); < foreach ($this->choices as $cid => $choice) { < $content = $choice->content; < if (ereg("^ [0-9] {1,3}=", $content,$ndd)) { < $n[$nameddegrees] = format_text(substr($content, strlen($ndd[0])), FORMAT_HTML); < $cidnamed[$cid] = true; < $nameddegrees++; < } < } < if ($nameddegrees && !$osgood) { < $colwidth = 80; < } else { < $colwidth = 40; < } < < for ($j = 0; $j < $this->length; $j++) { < if (isset($n [$j] )) { < $str = $n[$j]; < } else { < $str = $j+1; < } < echo '<td style="width:'.$colwidth.'; text-align:center" class="'.$bg.'">'.$str.'</td>'; < if ($bg == 'qntype c0') { < $bg = 'qntype c1'; < } else { < $bg = 'qntype c0'; < } < } < if ($this->precise == 1) { < echo '<td style="width:'.$colwidth.'; text-align:center" class="'.$bg.'">'.get_string('notapplicable', 'questionnaire').'</td>'; < } < echo '</tr>'; < < foreach ($this->choices as $cid => $choice) { < // do not print column names if named column exist < if (!array_key_exists($cid, $cidnamed)) { < $str = 'q'."{$this->id}_$cid"; < echo '<tr>'; < $content = $choice->content; < $contents = setl_choice_values($content); — > $contents = choice_values($content); 2205c1917 < $contents = setl_choice_values($content); — > $contents = choice_values($content); 2232,2365d1943 < < // Murphy Debug 20091007 < // Major hacked for Rank SD (standard deviation) display < function mkresavgsd($total, $precision, $showTotals, $length) { < global $CFG; < < $stravg = '<div style="text-align:center">'.get_string('averagerank', 'questionnaire').'</div>'; < $isna = $this->precise == 1; < $isnahead = ''; < $osgood = false; < if ($precision == 3) { // Osgood's semantic differential < $osgood = true; < } < < if ($isna) { < $isnahead = get_string('notapplicable', 'questionnaire').'<br />(#)'; < } < $table = new Object(); < < $table->align = array('', 'left', 'right', 'center'); < if ($isna) { < $table->head = array('', $stravg, '',$isnahead); < } else { < if ($osgood) { < $table->head = array('', $stravg, '', ''); < } else { < // $table->head = array('', $stravg, ''); < $table->head = array('', $stravg, get_string('mean', 'questionnaire'), get_string('standarddeviation', 'questionnaire')); < } < } < if (!$osgood) { < $rightcolwidth = '5%'; < } else { < $rightcolwidth = '25%'; < } < $table->size = array('*', '40%', $rightcolwidth,'5%'); < < $image_url = $CFG->wwwroot.'/mod/questionnaire/images/'; < $currhbar = $this->theme_bars_url(); < < if (!$length) { < $length = 5; < } < $nacol = 0; < $width = 100 / $length ; < $n = array(); < $nameddegrees = 0; < foreach ($this->choices as $choice) { < // to take into account languages filter < $content = (format_text($choice->content, FORMAT_HTML)); < if (ereg("^ [0-9] {1,3}=", $content,$ndd)) { < $n[$nameddegrees] = substr($content, strlen($ndd[0])); < $nameddegrees++; < } < } < $align = 'center'; < for ($j = 0; $j < $this->length; $j++) { < if (isset($n [$j] )) { < $str = $n[$j]; < } else { < $str = $j+1; < } < } < $out = '<table style="width:100%" cellpadding="2" cellspacing="0" border="1"><tr>'; < for ($i = 0; $i <= $length - 1; $i++) { < if (isset($n [$i] )) { < $str = $n[$i]; < } else { < $str = $i + 1; < } < $out .= '<td align = "center" style="width:'.$width.'%" >'.$str.'</td>'; < } < $out .= '</tr></table>'; < // $table->data[] = array('', $out, ''); < $table->data[] = array('', $out, '', ''); < < if (!empty($this->counts) && is_array($this->counts)) { < while(list($content) = each($this->counts)) { < < // eliminate potential named degrees on Likert scale < if (!ereg("^ [0-9] {1,3} =", $content)) { < if (isset($this->counts [$content] ->avg)) { < $avg = $this->counts[$content]->avg; < $mean = $this->counts[$content]->mean; < $sd = $this->counts[$content]->sd; < } else { < $avg = ''; < $mean = ''; < $sd = ''; < } < $nbna = $this->counts [$content] ->nbna; < < if($avg) { < $out = ''; < if (($j = $avg * $width) > 0) { < $interval = 50 / $length; < $out .= sprintf('<img alt="" src="'.$image_url.$currhbar. < 'rhbar.gif" height="0" width="%d%%" style="visibility:hidden" />', $j - $interval - 0.3); < } < $out .= '<img alt="" src="'.$image_url.$currhbar.'rhbar.gif" height="12" width="6" />'; < } else { < $out = ''; < } < < $contents = setl_choice_values($content); < if ($contents->modname) { < $content = $contents->text; < } < if ($osgood) { < list($content, $contentright) = split('[|]', $content); < } < if (!$isna) { < if ($osgood) { < // $table->data[] = array('<div align="right">'.format_text($content, FORMAT_HTML).'</div>', $out, '<div align="left"><strong>'.format_text($contentright, FORMAT_HTML).'</strong></div>', sprintf('%.1f', $avg)); < $table->data[] = array('<div align="right">'.format_text($content, FORMAT_HTML).'</div>', $out, '<div align="left"><strong>'.format_text($contentright, FORMAT_HTML).'</strong></div>', sprintf('%.1f', $mean), sprintf('(%.1f)', $sd)); < } else { < // $table->data[] = array(format_text($content, FORMAT_HTML), $out, sprintf('%.1f', $avg)); < $table->data[] = array(format_text($content, FORMAT_HTML), $out, sprintf('%.1f', $mean), sprintf('(%.1f)', $sd)); < } < } else { < if ($avg) { < $avg = sprintf('%.1f', $avg); < } < $table->data[] = array(format_text($content, FORMAT_HTML), $out, $avg, $nbna); < } < } // end if named degrees < } // end while < } else { < $table->data[] = array('', get_string('noresponsedata', 'questionnaire')); < } < print_table($table); < } < < 6) ~lang/en_utf8/questionnaire.php [root@centos5 en_utf8] # diff setlquestionnaire.php.unix questionnaire.php.ori 1c1 < <?php // $Id: setlquestionnaire.php,v 1.10.2.16 2009/03/17 14:18:51 joseph_rezeau Exp $ — > <?php // $Id: questionnaire.php,v 1.10.2.16 2009/03/17 14:18:51 joseph_rezeau Exp $ 44d43 < $string ['distinctrecord'] = 'distinct record(s)'; 76d74 < $string ['mean'] = 'Mean'; 81,84c79,80 < < $string ['modulename'] = 'SETL Questionnaire'; < $string ['modulenameplural'] = 'SETL Questionnaires'; < — > $string ['modulename'] = 'Questionnaire'; > $string ['modulenameplural'] = 'Questionnaires'; 172d167 < $string ['ratescale_sd'] = 'Rate (scale 1..100)'; 211,230d205 < < $string ['setlquestionnaire'] = 'SETL Questionnaire'; < $string ['setlquestionnaire:copysurveys'] = 'Copy template and private questionnaires'; < $string ['setlquestionnaire:createpublic'] = 'Create public questionnaires'; < $string ['setlquestionnaire:createtemplates'] = 'Create template questionnaires'; < $string ['setlquestionnaire:deleteresponses'] = 'Delete any response'; < $string ['setlquestionnaire:downloadresponses'] = 'Download responses in a CSV file'; < $string ['setlquestionnaire:editquestions'] = 'Create and edit questionnaire questions'; < $string ['setlquestionnaire:manage'] = 'Create and edit questionnaires'; < $string ['setlquestionnaire:printblank'] = 'Print blank questionnaire'; < $string ['setlquestionnaire:readallresponseanytime'] = 'Read all responses any time'; < $string ['setlquestionnaire:readallresponses'] = 'Read response summaries, subject to open times'; < $string ['setlquestionnaire:readownresponses'] = 'Read own responses'; < $string ['setlquestionnaire:submit'] = 'Complete and submit a questionnaire'; < $string ['setlquestionnaire:view'] = 'View a questionnaire'; < $string ['setlquestionnaire:viewsingleresponse'] = 'View complete individual responses'; < $string ['setlquestionnairecloses'] = 'Questionnaire Closes'; < $string ['setlquestionnaireopens'] = 'Questionnaire Opens'; < $string ['setlquestionnairereport'] = 'Questionnaire Report'; < 233d207 < $string ['standarddeviation'] = 'Standard deviation'; 276d249 < Actually, my colleague prefer repackage the module as a new one so that the original questionnaire module can leave unchanged. This SETL can only be used by the course administrator for asking the questions about the course & teacher's performance. It is sensitive to teacher and therefore we restrict teacher's access to this setlquestionnaire module. Thanks. Regards, Murphy Mr. Murphy C.K. Wong Senior IT Manager Centre for Information Technology in Education (CITE), Faculty of Education, HKU Office: Rm 110, Runme Shaw Bldg, CITE, HKU Tel: (852)-2241-5669, Fax: (852)-2517-7194 ---- Original Message ---- From: Mike Churchward (Moodle Tracker) contrib@moodle.org Sent: Saturday, January 09, 2010 4:28 AM To: murphy.wong@hku.hk Subject: [Moodle] Commented: ( CONTRIB-1715 ) Mean and standard deviation calculation (5 point scale) [ http://tracker.moodle.org/browse/CONTRIB-1715?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=79550#action_79550 ] Mike Churchward commented on CONTRIB-1715 : ------------------------------------------ Can you provide diffs of the code you changed? > Mean and standard deviation calculation (5 point scale) > ------------------------------------------------------- > > Key: CONTRIB-1715 > URL: http://tracker.moodle.org/browse/CONTRIB-1715 > Project: Non-core contributed modules > Issue Type: New Feature > Components: Module: Questionnaire > Affects Versions: 1.9.5 > Reporter: Murphy Wong > Assignee: Mike Churchward > Attachments: setlquestionnaire.tar.gz > > > Dear all, > I have repackaged the questionnaire module as setlquestionnare to include the following features for our SETL (student evaluation of teaching): > 1) Adding a new response type "Rate (scale 1..100)" using a hard coded 5 point scale at (0, 25, 50, 75, 100). Using this option, the responses will be displayed with mean and standard deviation in the result table; > 2) Only the last response from a student will be used for calculation. This is to avoid a single student from submitting too many entries for affect the result); and > 3) This is a separate module on Moodle so that we can change the permission to allow only administrator to see the SETL result. Teacher can continue using the ordinary questionnaire module. > I'm not sure if any other institutes may have similar requirement. Source code is attached below. Thanks. > Regards, > Murphy Wong
        Hide
        Murphy Wong added a comment -

        A bug fixed version.

        Show
        Murphy Wong added a comment - A bug fixed version.
        Hide
        Murphy Wong added a comment -

        Dear all,

        With the help from Anthony Borrow (http://docs.moodle.org/en/Development:How_to_create_a_patch), a patch file comparing the difference between the Questionnaire module and the SETLQuestionnaire is attached. Hope this is helpful to other users. Thanks Anthony.

        Regards,
        Murphy

        Show
        Murphy Wong added a comment - Dear all, With the help from Anthony Borrow ( http://docs.moodle.org/en/Development:How_to_create_a_patch ), a patch file comparing the difference between the Questionnaire module and the SETLQuestionnaire is attached. Hope this is helpful to other users. Thanks Anthony. Regards, Murphy
        Hide
        Murphy Wong added a comment -

        A Moodle 2.0 version of the setlquestionaire (based on version 2010110101) & a patch file is attached.

        Show
        Murphy Wong added a comment - A Moodle 2.0 version of the setlquestionaire (based on version 2010110101) & a patch file is attached.
        Hide
        Murphy Wong added a comment -

        For Moodle2 SETL, please try http://tracker.moodle.org/browse/CONTRIB-3265

        Show
        Murphy Wong added a comment - For Moodle2 SETL, please try http://tracker.moodle.org/browse/CONTRIB-3265

          People

          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development