Annotation of loncom/interface/statistics/lonstudentassessment.pm, revision 1.31
1.1 stredwic 1: # The LearningOnline Network with CAPA
2: #
1.31 ! matthew 3: # $Id: lonstudentassessment.pm,v 1.30 2003/02/28 21:19:00 matthew Exp $
1.1 stredwic 4: #
5: # Copyright Michigan State University Board of Trustees
6: #
7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
8: # LON-CAPA is free software; you can redistribute it and/or modify
9: # it under the terms of the GNU General Public License as published by
10: # the Free Software Foundation; either version 2 of the License, or
11: # (at your option) any later version.
12: #
13: # LON-CAPA is distributed in the hope that it will be useful,
14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: # GNU General Public License for more details.
17: #
18: # You should have received a copy of the GNU General Public License
19: # along with LON-CAPA; if not, write to the Free Software
20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21: #
22: # /home/httpd/html/adm/gpl.txt
23: #
24: # http://www.lon-capa.org/
25: #
26: # (Navigate problems for statistical reports
1.28 matthew 27: #
28: #######################################################
29: #######################################################
30:
31: =pod
32:
33: =head1 NAME
34:
35: lonstudentassessment
36:
37: =head1 SYNOPSIS
38:
39: Presents assessment data about a student or a group of students.
40:
41: =head1 Subroutines
42:
43: =over 4
44:
45: =cut
46:
47: #######################################################
48: #######################################################
1.1 stredwic 49:
1.21 minaeibi 50: package Apache::lonstudentassessment;
1.1 stredwic 51:
52: use strict;
1.28 matthew 53: use Apache::lonstatistics;
1.1 stredwic 54: use Apache::lonhtmlcommon;
55: use Apache::loncoursedata;
1.28 matthew 56: use Apache::lonnet; # for logging porpoises
1.31 ! matthew 57: use Spreadsheet::WriteExcel;
! 58:
! 59: #######################################################
! 60: #######################################################
! 61: =pod
! 62:
! 63: =item Package Variables
! 64:
! 65: =over 4
! 66:
! 67: =item $Statistics Hash ref to store student data. Indexed by symb,
! 68: contains hashes with keys 'score' and 'max'.
! 69:
! 70: =cut
! 71:
! 72: #######################################################
! 73: #######################################################
1.1 stredwic 74:
1.30 matthew 75: my $Statistics;
76:
1.28 matthew 77: #######################################################
78: #######################################################
79:
80: =pod
81:
1.31 ! matthew 82: =item $show_links 'yes' or 'no' for linking to student performance data
! 83:
! 84: =item $output_mode 'html', 'excel', or 'csv' for output mode
! 85:
! 86: =item $show 'all' or 'totals' determines how much data is output
! 87:
! 88: =cut
! 89:
! 90: #######################################################
! 91: #######################################################
! 92: my $show_links;
! 93: my $output_mode;
! 94: my $show;
1.28 matthew 95:
1.31 ! matthew 96: #######################################################
! 97: #######################################################
! 98: # End of package variable declarations
1.28 matthew 99:
1.31 ! matthew 100: =pod
1.28 matthew 101:
1.31 ! matthew 102: =back
1.28 matthew 103:
1.31 ! matthew 104: =cut
1.28 matthew 105:
1.31 ! matthew 106: #######################################################
! 107: #######################################################
1.28 matthew 108:
1.31 ! matthew 109: =pod
1.28 matthew 110:
1.31 ! matthew 111: =item &BuildStudentAssessmentPage()
1.28 matthew 112:
1.31 ! matthew 113: Inputs:
1.4 stredwic 114:
1.31 ! matthew 115: =over 4
1.28 matthew 116:
117: =item $r Apache Request
118:
119: =item $c Apache Connection
120:
121: =back
122:
123: =cut
124:
125: #######################################################
126: #######################################################
1.1 stredwic 127: sub BuildStudentAssessmentPage {
1.30 matthew 128: my ($r,$c)=@_;
129: undef($Statistics);
130: #
1.31 ! matthew 131: # Print out the HTML headers for the interface
! 132: # This also parses the output mode selector
! 133: # This step must always be done.
1.30 matthew 134: $r->print(&CreateInterface());
1.31 ! matthew 135: $r->print('<input type="hidden" name="notfirstrun" value="true" />');
1.7 stredwic 136: $r->rflush();
1.31 ! matthew 137: if (! exists($ENV{'form.notfirstrun'})) {
! 138: $r->print(<<ENDMSG);
! 139: <p>
! 140: <font size="+1">
! 141: Please make your selections in the boxes above and hit
! 142: the button marked "Update Display".
! 143: </font>
! 144: </p>
! 145: ENDMSG
! 146: return;
! 147: }
! 148: #
! 149: #
! 150: my $initialize = \&html_initialize;
! 151: my $output_student = \&html_outputstudent;
! 152: my $finish = \&html_finish;
! 153: #
! 154: if ($output_mode eq 'excel') {
! 155: $initialize = \&excel_initialize;
! 156: $output_student = \&excel_outputstudent;
! 157: $finish = \&excel_finish;
! 158: } elsif ($output_mode eq 'csv') {
! 159: $initialize = \&csv_initialize;
! 160: $output_student = \&csv_outputstudent;
! 161: $finish = \&csv_finish;
! 162: }
1.30 matthew 163: #
164: if($c->aborted()) { return ; }
1.31 ! matthew 165: #
! 166: # Call the initialize routine selected above
! 167: $initialize->($r);
1.30 matthew 168: foreach my $student (@Apache::lonstatistics::Students) {
1.31 ! matthew 169: if($c->aborted()) {
! 170: $finish->($r);
! 171: return ;
1.1 stredwic 172: }
1.31 ! matthew 173: # Call the output_student routine selected above
! 174: $output_student->($r,$student);
! 175: }
! 176: # Call the "finish" routine selected above
! 177: $finish->($r);
! 178: #
! 179: return;
! 180: }
! 181:
! 182: #######################################################
! 183: #######################################################
1.30 matthew 184:
1.31 ! matthew 185: sub get_student_fields_to_show {
! 186: my @to_show = @Apache::lonstatistics::SelectedStudentData;
! 187: foreach (@to_show) {
! 188: if ($_ eq 'all') {
! 189: @to_show = @Apache::lonstatistics::StudentDataOrder;
! 190: last;
! 191: }
! 192: }
! 193: return @to_show;
! 194: }
! 195:
! 196: sub get_sequences_to_show {
! 197: my @Sequences;
! 198: foreach my $map_symb (@Apache::lonstatistics::SelectedMaps) {
! 199: foreach my $sequence (@Apache::lonstatistics::Sequences) {
! 200: next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
! 201: next if ($sequence->{'num_assess'} < 1);
! 202: push (@Sequences,$sequence);
! 203: }
1.1 stredwic 204: }
1.31 ! matthew 205: return @Sequences;
1.2 stredwic 206: }
1.30 matthew 207:
1.31 ! matthew 208:
1.28 matthew 209: #######################################################
210: #######################################################
211:
212: =pod
1.2 stredwic 213:
1.28 matthew 214: =item &CreateInterface()
1.21 minaeibi 215:
1.28 matthew 216: Called by &BuildStudentAssessmentPage to create the top part of the
217: page which displays the chart.
218:
1.30 matthew 219: Inputs: None
1.28 matthew 220:
221: Returns: A string containing the HTML for the headers and top table for
222: the chart page.
223:
224: =cut
225:
226: #######################################################
227: #######################################################
1.2 stredwic 228: sub CreateInterface {
1.4 stredwic 229: my $Str = '';
1.30 matthew 230: # $Str .= &CreateLegend();
231: $Str .= '<table cellspacing="5">'."\n";
232: $Str .= '<tr>';
233: $Str .= '<td align="center"><b>Sections</b></td>';
234: $Str .= '<td align="center"><b>Student Data</b></td>';
235: $Str .= '<td align="center"><b>Sequences and Folders</b></td>';
1.31 ! matthew 236: $Str .= '<td align="center"><b>Output Format</b></td>';
1.30 matthew 237: $Str .= '</tr>'."\n";
238: #
1.4 stredwic 239: $Str .= '<tr><td align="center">'."\n";
1.29 matthew 240: $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
1.4 stredwic 241: $Str .= '</td><td align="center">';
1.30 matthew 242: my $only_seq_with_assessments = sub {
243: my $s=shift;
244: if ($s->{'num_assess'} < 1) {
245: return 0;
246: } else {
247: return 1;
248: }
249: };
250: $Str .= &Apache::lonstatistics::StudentDataSelect('StudentData','multiple',
251: 5,undef);
1.4 stredwic 252: $Str .= '</td><td>'."\n";
1.30 matthew 253: $Str .= &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
254: $only_seq_with_assessments);
1.31 ! matthew 255: $Str .= '</td><td>'."\n";
! 256: $Str .= &CreateAndParseOutputSelector();
1.30 matthew 257: $Str .= '</td></tr>'."\n";
258: $Str .= '</table>'."\n";
1.4 stredwic 259: return $Str;
1.1 stredwic 260: }
1.30 matthew 261:
262: #######################################################
263: #######################################################
264:
265: =pod
266:
1.31 ! matthew 267: =item &CreateAndParseOutputSelector()
1.30 matthew 268:
269: =cut
270:
271: #######################################################
272: #######################################################
1.31 ! matthew 273: sub CreateAndParseOutputSelector {
! 274: my $Str = '';
! 275: my $elementname = 'outputmode';
! 276: #
! 277: # Format for output options is 'mode, restrictions';
! 278: my @Options = ('html, with links','html, without links',
! 279: 'html, totals only','excel, totals only',
! 280: 'csv, totals only','csv, everything');
! 281: my $selected = 'html, with links';
! 282: if (exists($ENV{'form.'.$elementname})) {
! 283: if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
! 284: $selected = $ENV{'form.'.$elementname}->[0];
! 285: } else {
! 286: $selected = $ENV{'form.'.$elementname};
! 287: }
! 288: }
! 289: #
! 290: # Set package variables describing output mode
! 291: $show_links = 'no';
! 292: $output_mode = 'html';
! 293: $show = 'all';
! 294: my ($mode,$restriction) = split(',',$selected);
! 295: $restriction =~ s/^\s*//;
! 296: if ($mode =~ /^(html|excel|csv)$/) {
! 297: $output_mode = $mode;
! 298: } else {
! 299: $output_mode = 'html';
! 300: }
! 301: if ($restriction eq 'with links') {
! 302: $show_links = 'yes';
! 303: } else {
! 304: $show_links = 'no';
! 305: }
! 306: if ($restriction eq 'totals only') {
! 307: $show = 'totals';
! 308: } else {
! 309: $show = 'everything';
! 310: }
! 311: #
! 312: # Build the form element
! 313: $Str = qq/<select size="5" name="$elementname">/;
! 314: foreach my $option (@Options) {
! 315: $Str .= qq/\n <option value="$option"/;
! 316: $Str .= " selected " if ($option eq $selected);
! 317: $Str .= ">$option<\/option>";
! 318: }
! 319: $Str .= "\n</select>";
! 320: return $Str;
! 321: }
1.30 matthew 322:
1.28 matthew 323: #######################################################
324: #######################################################
1.1 stredwic 325:
1.28 matthew 326: =pod
327:
1.31 ! matthew 328: =head2 HTML output routines
1.28 matthew 329:
1.31 ! matthew 330: =item &html_initialize($r)
1.28 matthew 331:
1.31 ! matthew 332: Create labels for the columns of student data to show.
1.28 matthew 333:
1.31 ! matthew 334: =item &html_outputstudent($r,$student)
1.28 matthew 335:
1.31 ! matthew 336: Return a line of the chart for a student.
1.28 matthew 337:
1.31 ! matthew 338: =item &html_finish($r)
1.28 matthew 339:
340: =cut
341:
342: #######################################################
343: #######################################################
1.31 ! matthew 344: {
! 345: my $padding;
! 346: my $count;
! 347:
! 348: sub html_initialize {
! 349: my ($r) = @_;
1.30 matthew 350: #
351: $padding = ' 'x3;
1.31 ! matthew 352: $count = 1;
1.30 matthew 353: #
1.31 ! matthew 354: my $Str = "<pre>\n";
1.30 matthew 355: # First, the @StudentData fields need to be listed
1.31 ! matthew 356: my @to_show = &get_student_fields_to_show();
1.30 matthew 357: foreach my $field (@to_show) {
358: my $title=$Apache::lonstatistics::StudentData{$field}->{'title'};
359: my $base =$Apache::lonstatistics::StudentData{$field}->{'base_width'};
360: my $width=$Apache::lonstatistics::StudentData{$field}->{'width'};
361: $Str .= $title.' 'x($width-$base).$padding;
362: }
363: # Now the selected sequences need to be listed
1.31 ! matthew 364: foreach my $sequence (&get_sequences_to_show) {
! 365: my $title = $sequence->{'title'};
! 366: my $base = $sequence->{'base_width'};
! 367: my $width = $sequence->{'width'};
! 368: $Str .= $title.' 'x($width-$base).$padding;
1.30 matthew 369: }
1.31 ! matthew 370: $Str .= "total (of shown problems)</pre>\n";
! 371: $Str .= "<pre>";
! 372: $r->print($Str);
! 373: $r->rflush();
! 374: return;
1.30 matthew 375: }
376:
1.31 ! matthew 377: sub html_outputstudent {
! 378: my ($r,$student) = @_;
1.2 stredwic 379: my $Str = '';
1.30 matthew 380: # First, the @StudentData fields need to be listed
1.31 ! matthew 381: my @to_show = &get_student_fields_to_show();
1.30 matthew 382: foreach my $field (@to_show) {
383: my $title=$student->{$field};
1.31 ! matthew 384: my $base = length($title);
1.30 matthew 385: my $width=$Apache::lonstatistics::StudentData{$field}->{'width'};
386: $Str .= $title.' 'x($width-$base).$padding;
387: }
388: # Get ALL the students data
389: my %StudentsData;
390: my @tmp = &Apache::loncoursedata::get_current_state
391: ($student->{'username'},$student->{'domain'},undef,
392: $ENV{'request.course.id'});
393: if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) {
394: %StudentsData = @tmp;
395: }
396: if (scalar(@tmp) < 1) {
397: $Str .= '<font color="blue">No Course Data</font>'."\n";
1.31 ! matthew 398: $r->print($Str);
! 399: $r->rflush();
! 400: return;
1.30 matthew 401: }
402: #
403: # By sequence build up the data
404: my $studentstats;
1.31 ! matthew 405: my $PerformanceStr = '';
! 406: foreach my $seq (&get_sequences_to_show) {
! 407: my ($performance,$score,$seq_max) =
! 408: &StudentPerformanceOnSequence($student,\%StudentsData,
! 409: $seq,$show_links);
! 410: my $ratio = $score.'/'.$seq_max;
! 411: #
! 412: if ($show eq 'totals') {
! 413: $performance = ' 'x(length($seq_max)-length($score)).$ratio;
! 414: $performance .= ' 'x($seq->{'width'}-length($performance));
! 415: } else {
! 416: # Pad with extra spaces
! 417: $performance .= ' 'x($seq->{'width'}-$seq_max-
! 418: length($ratio)
! 419: ).$ratio;
1.30 matthew 420: }
1.31 ! matthew 421: #
! 422: $Str .= $performance.$padding;
! 423: #
! 424: $studentstats->{$seq->{'symb'}}->{'score'}= $score;
! 425: $studentstats->{$seq->{'symb'}}->{'max'} = $seq_max;
1.30 matthew 426: }
427: #
428: # Total it up and store the statistics info.
429: my ($score,$max) = (0,0);
430: while (my ($symb,$seq_stats) = each (%{$studentstats})) {
431: $Statistics->{$symb}->{'score'} += $seq_stats->{'score'};
432: $Statistics->{$symb}->{'max'} += $seq_stats->{'max'};
433: $score += $seq_stats->{'score'};
434: $max += $seq_stats->{'max'};
435: }
1.31 ! matthew 436: $Str .= ' '.' 'x(length($max)-length($score)).$score.'/'.$max;
1.30 matthew 437: $Str .= " \n";
1.31 ! matthew 438: $r->print($Str);
! 439: #
! 440: $count++;
! 441: if($count % 5 == 0) {
! 442: $r->print("</pre><pre>");
! 443: }
! 444: #
! 445: $r->rflush();
! 446: return;
1.30 matthew 447: }
1.2 stredwic 448:
1.31 ! matthew 449: sub html_finish {
! 450: my ($r) = @_;
! 451: $r->print("</pre>\n");
! 452: $r->rflush();
! 453: return;
! 454: }
! 455:
! 456: }
! 457:
! 458: #######################################################
! 459: #######################################################
! 460:
! 461: =pod
! 462:
! 463: =head2 EXCEL subroutines
! 464:
! 465: =item &excel_initialize($r)
! 466:
! 467: =item &excel_outputstudent($r,$student)
! 468:
! 469: =item &excel_finish($r)
! 470:
! 471: =cut
! 472:
! 473: #######################################################
! 474: #######################################################
! 475: {
! 476:
! 477: my $excel_sheet;
! 478:
! 479: sub excel_initialize {
! 480: my ($r) = @_;
! 481: #
! 482: $r->print("<h1>Not implemented yet</h1>");
! 483: return;
! 484: my $filename = '/prtspool/'.
! 485: $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
! 486: time.'_'.rand(1000000000).'.xls';
! 487: $excel_sheet = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
! 488: if (! defined($excel_sheet)) {
! 489: $r->log_error("Error creating excel spreadsheet $filename: $!");
! 490: $r->print("Problems creating new Excel file. ".
! 491: "This error has been logged. ".
! 492: "Please alert your LON-CAPA administrator");
! 493: return 0;
! 494: }
! 495: #
! 496: # The excel spreadsheet stores temporary data in files, then put them
! 497: # together. If needed we should be able to disable this (memory only).
! 498: # The temporary directory must be specified before calling 'addworksheet'.
! 499: # File::Temp is used to determine the temporary directory.
! 500: $excel_sheet->set_tempdir($Apache::lonnet::tmpdir);
! 501: #
! 502: # Determine the name to give the worksheet
! 503: # $excel_sheet->addworksheet();
! 504:
! 505: return;
! 506: }
! 507:
! 508: sub excel_outputstudent {
! 509: my ($r,$student) = @_;
! 510: }
! 511:
! 512: sub excel_finish {
! 513: my ($r) = @_;
! 514: }
! 515:
! 516: }
1.30 matthew 517: #######################################################
518: #######################################################
519:
520: =pod
521:
1.31 ! matthew 522: =head2 CSV output routines
! 523:
! 524: =item &csv_initialize($r)
! 525:
! 526: =item &csv_outputstudent($r,$student)
! 527:
! 528: =item &csv_finish($r)
1.30 matthew 529:
530: =cut
531:
532: #######################################################
533: #######################################################
1.31 ! matthew 534: {
! 535:
! 536: sub csv_initialize{
! 537: my ($r) = @_;
! 538: $r->print("<h1>Not implemented yet</h1>");
! 539: return;
! 540: }
! 541:
! 542: sub csv_outputstudent {
! 543: my ($r,$student) = @_;
! 544: }
! 545:
! 546: sub csv_finish {
! 547: my ($r) = @_;
! 548: }
1.2 stredwic 549:
550: }
551:
1.28 matthew 552: #######################################################
553: #######################################################
554:
1.2 stredwic 555: =pod
556:
1.30 matthew 557: =item &StudentPerformanceOnSequence()
1.2 stredwic 558:
1.30 matthew 559: Inputs:
1.2 stredwic 560:
561: =over 4
562:
1.30 matthew 563: =item $student
1.28 matthew 564:
1.30 matthew 565: =item $studentdata Hash ref to all student data
1.2 stredwic 566:
1.30 matthew 567: =item $seq Hash ref, the sequence we are working on
1.2 stredwic 568:
1.30 matthew 569: =item $links if defined we will output links to each resource.
1.2 stredwic 570:
1.28 matthew 571: =back
1.2 stredwic 572:
573: =cut
1.1 stredwic 574:
1.28 matthew 575: #######################################################
576: #######################################################
1.30 matthew 577: sub StudentPerformanceOnSequence {
1.31 ! matthew 578: my ($student,$studentdata,$seq,$links,$totalonly) = @_;
! 579: $totalonly = 0 if (! defined($totalonly));
! 580: $links = 'no' if (! defined($links));
1.1 stredwic 581: my $Str = '';
1.30 matthew 582: my ($sum,$max) = (0,0);
583: foreach my $resource (@{$seq->{'contents'}}) {
584: next if ($resource->{'type'} ne 'assessment');
585: my $resource_data = $studentdata->{$resource->{'symb'}};
586: my $value = '';
587: foreach my $partnum (@{$resource->{'parts'}}) {
588: $max++;
589: my $symbol = ' '; # default to space
590: #
591: if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {
592: my $status = $resource_data->{'resource.'.$partnum.'.solved'};
593: if ($status eq 'correct_by_override') {
594: $symbol = '+';
595: $sum++;
596: } elsif ($status eq 'incorrect_by_override') {
597: $symbol = '-';
598: } elsif ($status eq 'ungraded_attempted') {
599: $symbol = '#';
600: } elsif ($status eq 'incorrect_attempted') {
601: $symbol = '.';
602: } elsif ($status eq 'excused') {
603: $symbol = 'x';
604: $max--;
605: } elsif ($status eq 'correct_by_student' &&
606: exists($resource_data->{'resource.'.$partnum.'.tries'})){
607: my $num = $resource_data->{'resource.'.$partnum.'.tries'};
608: if ($num > 9) {
609: $symbol = '*';
610: } elsif ($num > 0) {
611: $symbol = $num;
612: } else {
613: $symbol = ' ';
614: }
615: $sum++;
616: } else {
617: $symbol = ' ';
1.2 stredwic 618: }
1.30 matthew 619: } else {
620: # Unsolved. Did they try?
621: if (exists($resource_data->{'resource.'.$partnum.'.tries'})){
622: $symbol = '.';
623: } else {
624: $symbol = ' ';
1.18 matthew 625: }
1.2 stredwic 626: }
1.30 matthew 627: #
1.31 ! matthew 628: if ($links eq 'yes' && $symbol ne ' ') {
1.30 matthew 629: $symbol = '<a href="/adm/grades'.
630: '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
631: '&student='.$student->{'username'}.
632: '&domain='.$student->{'domain'}.
633: '&command=submission">'.$symbol.'</a>';
634: }
635: $value .= $symbol;
1.2 stredwic 636: }
1.30 matthew 637: $Str .= $value;
1.17 minaeibi 638: }
1.30 matthew 639: return ($Str,$sum,$max);
1.17 minaeibi 640: }
641:
1.28 matthew 642: #######################################################
643: #######################################################
1.17 minaeibi 644: sub StudentAverageTotal {
1.21 minaeibi 645: my ($cache, $students, $sequenceKeys)=@_;
1.23 minaeibi 646: my $Str = "\n<b>Summary Tables:</b>\n";
1.21 minaeibi 647: my %Correct = ();
648: my $ProblemsSolved = 0;
649: my $TotalProblems = 0;
650: my $StudentCount = 0;
651:
652: foreach my $name (@$students) {
653: $StudentCount++;
654: foreach my $sequence (@$sequenceKeys) {
1.23 minaeibi 655: $Correct{$sequence} +=
656: $cache->{$name.':'.$sequence.':problemsCorrect'};
1.17 minaeibi 657: }
1.21 minaeibi 658: $ProblemsSolved += $cache->{$name.':problemsSolved'};
659: $TotalProblems += $cache->{$name.':totalProblems'};
1.1 stredwic 660: }
1.25 matthew 661: if ($StudentCount) {
1.27 minaeibi 662: $ProblemsSolved = sprintf( "%.2f",
663: $ProblemsSolved/$StudentCount);
1.25 matthew 664: $TotalProblems /= $StudentCount;
665: } else {
666: $ProblemsSolved = 0;
667: $TotalProblems = 0;
668: }
1.27 minaeibi 669:
1.24 minaeibi 670: $Str .= '<table border=2 cellspacing="1">'."\n";
1.23 minaeibi 671: $Str .= '<tr><td><b>Students Count</b></td><td><b>'.
672: $StudentCount.'</b></td></tr>'."\n";
673: $Str .= '<tr><td><b>Total Problems</b></td><td><b>'.
674: $TotalProblems.'</b></td></tr>'."\n";
675: $Str .= '<tr><td><b>Average Correct</b></td><td><b>'.
676: $ProblemsSolved.'</b></td></tr>'."\n";
677: $Str .= '</table>'."\n";
678:
1.24 minaeibi 679: $Str .= '<table border=2 cellspacing="1">'."\n";
1.23 minaeibi 680: $Str .= '<tr><th>Title</th><th>Total Problems</th>'.
681: '<th>Average Correct</th></tr>'."\n";
682: foreach my $S(@$sequenceKeys) {
683: my $title=$cache->{$S.':title'};
684: #$Str .= $cache->{$S.':problems'};
1.24 minaeibi 685: #my @problems=split(':', $cache->{$S.':problems'});
1.23 minaeibi 686: #my $pCount=scalar @problems;
687: my $pCount=MaxSeqPr($cache,@$students[0],$S);
1.25 matthew 688: my $crr;
689: if ($StudentCount) {
690: $crr=sprintf( "%.2f", $Correct{$S}/$StudentCount );
691: } else {
692: $crr="0.00";
693: }
1.23 minaeibi 694: $Str .= '<tr><td>'.$title.
695: '</td><td align=center>'.$pCount.
696: '</td><td align=center>'.$crr.
697: '</td></tr>'."\n";
1.10 stredwic 698: }
1.1 stredwic 699:
1.23 minaeibi 700: $Str .= '</table>'."\n";
701:
1.1 stredwic 702: return $Str;
703: }
1.23 minaeibi 704:
1.28 matthew 705: #######################################################
706: #######################################################
1.23 minaeibi 707:
1.2 stredwic 708: =pod
709:
710: =item &CreateLegend()
711:
712: This function returns a formatted string containing the legend for the
713: chart. The legend describes the symbols used to represent grades for
714: problems.
715:
716: =cut
717:
1.28 matthew 718: #######################################################
719: #######################################################
1.2 stredwic 720: sub CreateLegend {
721: my $Str = "<p><pre>".
1.13 minaeibi 722: " 1 correct by student in 1 try\n".
723: " 7 correct by student in 7 tries\n".
1.12 minaeibi 724: " * correct by student in more than 9 tries\n".
1.20 minaeibi 725: " + correct by hand grading or override\n".
1.12 minaeibi 726: " - incorrect by override\n".
727: " . incorrect attempted\n".
728: " # ungraded attempted\n".
1.13 minaeibi 729: " not attempted (blank field)\n".
1.12 minaeibi 730: " x excused".
1.17 minaeibi 731: "</pre><p>";
1.2 stredwic 732: return $Str;
733: }
734:
1.28 matthew 735: #######################################################
736: #######################################################
737:
1.30 matthew 738: =pod
1.2 stredwic 739:
740: =back
741:
742: =cut
743:
1.28 matthew 744: #######################################################
745: #######################################################
1.2 stredwic 746:
1.28 matthew 747: 1;
1.2 stredwic 748:
1.1 stredwic 749: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>