Diff for /loncom/interface/statistics/lonstudentassessment.pm between versions 1.31 and 1.36

version 1.31, 2003/03/03 19:28:29 version 1.36, 2003/03/06 21:12:54
Line 83  my $Statistics; Line 83  my $Statistics;
   
 =item $output_mode 'html', 'excel', or 'csv' for output mode  =item $output_mode 'html', 'excel', or 'csv' for output mode
   
 =item $show 'all' or 'totals' determines how much data is output  =item $show 'all', 'totals', or 'scores' determines how much data is output
   
 =cut  =cut
   
Line 143  the button marked "Update Disp Line 143  the button marked "Update Disp
 </font>  </font>
 </p>  </p>
 ENDMSG  ENDMSG
   #        $r->print(&OutputDescriptions());
         return;          return;
     }      }
     #      #
Line 155  ENDMSG Line 156  ENDMSG
         $initialize     = \&excel_initialize;          $initialize     = \&excel_initialize;
         $output_student = \&excel_outputstudent;          $output_student = \&excel_outputstudent;
         $finish         = \&excel_finish;          $finish         = \&excel_finish;
       } elsif ($output_mode eq 'multi-sheet excel') {
           $initialize     = \&multi_sheet_excel_initialize;
           $output_student = \&multi_sheet_excel_outputstudent;
           $finish         = \&multi_sheet_excel_finish;
     } elsif ($output_mode eq 'csv') {      } elsif ($output_mode eq 'csv') {
         $initialize     = \&csv_initialize;          $initialize     = \&csv_initialize;
         $output_student = \&csv_outputstudent;          $output_student = \&csv_outputstudent;
Line 232  sub CreateInterface { Line 237  sub CreateInterface {
     $Str .= '<tr>';      $Str .= '<tr>';
     $Str .= '<td align="center"><b>Sections</b></td>';      $Str .= '<td align="center"><b>Sections</b></td>';
     $Str .= '<td align="center"><b>Student Data</b></td>';      $Str .= '<td align="center"><b>Student Data</b></td>';
     $Str .= '<td align="center"><b>Sequences and Folders</b></td>';      $Str .= '<td align="center"><b>Problem Sets</b></td>';
     $Str .= '<td align="center"><b>Output Format</b></td>';      $Str .= '<td align="center"><b>Output Format</b></td>';
     $Str .= '</tr>'."\n";      $Str .= '</tr>'."\n";
     #      #
Line 270  sub CreateInterface { Line 275  sub CreateInterface {
   
 #######################################################  #######################################################
 #######################################################  #######################################################
   my @OutputOptions = 
       ({ name  => 'HTML, with links',
          value => 'html, with links',
          description => 'Output HTML with each symbol linked to the problem '.
      'which generated it.',
          mode => 'html',
          show => 'all',
          show_links => 'yes',
          },
        { name  => 'HTML, without links',
          value => 'html, without links',
          description => 'Output HTML.  By not including links, the size of the'.
      ' web page is greatly reduced.  If your browser crashes on the '.
      'full display, try this.',
          mode => 'html',
          show => 'all',
          show_links => 'no',
              },
        { name  => 'HTML, scores only',
          value => 'html, scores only',
          description => 'Output HTML, only showing the total number of correct'.
      ' problems (or problem parts) and not the maximum possible for '.
      'each student',
          mode => 'html',
          show => 'scores',
          show_links => 'no',
              },
        { name  => 'HTML, totals',
          value => 'html, totals',
          description => 'Output HTML, but only the summary statistics for each'.
      ' sequence selected.',
          mode => 'html',
          show => 'totals',
          show_links => 'no',
          },
        { name  => 'Excel, scores only',
          value => 'excel, scores only',
          description => 'Output an Excel file (compatable with Excel 95), '.
      'with a single column for each sequence showing the students '.
      'score.',
          mode => 'excel',
          show => 'scores',
          show_links => 'no',
              },
        { name  => 'Excel, totals',
          value => 'excel, totals',
          description => 'Output an Excel file (compatable with Excel 95), '.
      'with two columns for each sequence, the students score on the '.
      'sequence and the students maximum possible on the sequence',
          mode => 'excel',
          show => 'totals',
          show_links => 'no',
              },
        { name  => 'multi-sheet Excel',
          value => 'multi-sheet excel',
          description => 'Output an Excel file (compatable with Excel 95), '.
      'with a seperate worksheet for each sequence you have selected '.
              'the data for each problem part '.
              '(number of tries, status, points awarded) will be listed.',
          mode => 'multi-sheet excel',
          show => 'totals',
          show_links => 'no',
              },
        { name  => 'multi-sheet Excel, by section',
          value => 'multi-sheet excel, by section',
          description => 'Output an Excel file (compatable with Excel 95), '.
      'with a seperate worksheet for each sequence you have selected '.
              'the data for each problem part '.
              '(number of tries, status, points awarded) will be listed.  '.
              'There will be one Excel workbook for each section selected.',
          mode => 'multi-sheet excel',
          show => 'by section',
          show_links => 'no',
              },
        { name  => 'CSV, everything',
          value => 'csv, everything',
          description => '',
          mode => 'csv',
          show => 'all',
          show_links => 'no',
              },
        { name  => 'CSV, scores only',
          value => 'csv, scores only',
          description => '',
          mode => 'csv',
          show => 'scores',
          show_links => 'no',
              },
        { name  => 'CSV, totals',
          value => 'csv, totals',
          description => '',
          mode => 'csv',
          show => 'totals',
          show_links => 'no',
              },
        );
   
   sub OutputDescriptions {
       my $Str = '';
       $Str .= "<h2>Output Modes</h2>\n";
       $Str .= "<dl>\n";
       foreach my $outputmode (@OutputOptions) {
    $Str .="    <dt>".$outputmode->{'name'}."</dt>\n";
    $Str .="        <dd>".$outputmode->{'description'}."</dd>\n";
       }
       $Str .= "</dl>\n";
       return $Str;
   }
   
 sub CreateAndParseOutputSelector {  sub CreateAndParseOutputSelector {
     my $Str = '';      my $Str = '';
     my $elementname = 'outputmode';      my $elementname = 'outputmode';
     #      #
     # Format for output options is 'mode, restrictions';      # Format for output options is 'mode, restrictions';
     my @Options = ('html, with links','html, without links',  
                    'html, totals only','excel, totals only',  
                    'csv, totals only','csv, everything');  
     my $selected = 'html, with links';      my $selected = 'html, with links';
     if (exists($ENV{'form.'.$elementname})) {      if (exists($ENV{'form.'.$elementname})) {
         if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {          if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
Line 291  sub CreateAndParseOutputSelector { Line 402  sub CreateAndParseOutputSelector {
     $show_links  = 'no';      $show_links  = 'no';
     $output_mode = 'html';      $output_mode = 'html';
     $show        = 'all';      $show        = 'all';
     my ($mode,$restriction) = split(',',$selected);      foreach my $option (@OutputOptions) {
     $restriction =~ s/^\s*//;          next if ($option->{'value'} ne $selected);
     if ($mode =~ /^(html|excel|csv)$/) {          $output_mode = $option->{'mode'};
         $output_mode = $mode;          $show        = $option->{'show'};
     } else {          $show_links  = $option->{'show_links'};
         $output_mode = 'html';  
     }  
     if ($restriction eq 'with links') {  
         $show_links = 'yes';  
     } else {  
         $show_links = 'no';  
     }  
     if ($restriction eq 'totals only') {  
         $show = 'totals';  
     } else {  
         $show = 'everything';  
     }      }
   
     #      #
     # Build the form element      # Build the form element
     $Str = qq/<select size="5" name="$elementname">/;      $Str = qq/<select size="5" name="$elementname">/;
     foreach my $option (@Options) {      foreach my $option (@OutputOptions) {
         $Str .= qq/\n    <option value="$option"/;          $Str .= "\n".'    <option value="'.$option->{'value'}.'"';
         $Str .= " selected " if ($option eq $selected);          $Str .= " selected " if ($option->{'value'} eq $selected);
         $Str .= ">$option<\/option>";          $Str .= ">".$option->{'name'}."<\/option>";
     }      }
     $Str .= "\n</select>";      $Str .= "\n</select>";
     return $Str;      return $Str;
Line 349  sub html_initialize { Line 450  sub html_initialize {
     my ($r) = @_;      my ($r) = @_;
     #      #
     $padding = ' 'x3;      $padding = ' 'x3;
     $count = 1;      $count = 0;
     #      #
     my $Str = "<pre>\n";      my $Str = "<pre>\n";
     # First, the @StudentData fields need to be listed      # First, the @StudentData fields need to be listed
Line 377  sub html_initialize { Line 478  sub html_initialize {
 sub html_outputstudent {  sub html_outputstudent {
     my ($r,$student) = @_;      my ($r,$student) = @_;
     my $Str = '';      my $Str = '';
       #
       if($count++ % 5 == 0 && $count > 0) {
           $r->print("</pre><pre>");
       }
     # First, the @StudentData fields need to be listed      # First, the @StudentData fields need to be listed
     my @to_show = &get_student_fields_to_show();      my @to_show = &get_student_fields_to_show();
     foreach my $field (@to_show) {      foreach my $field (@to_show) {
Line 412  sub html_outputstudent { Line 517  sub html_outputstudent {
         if ($show eq 'totals') {          if ($show eq 'totals') {
             $performance = ' 'x(length($seq_max)-length($score)).$ratio;              $performance = ' 'x(length($seq_max)-length($score)).$ratio;
             $performance .= ' 'x($seq->{'width'}-length($performance));              $performance .= ' 'x($seq->{'width'}-length($performance));
           } elsif ($show eq 'scores') {
               $performance = $score;
               $performance .= ' 'x($seq->{'width'}-length($performance));
         } else {          } else {
             # Pad with extra spaces              # Pad with extra spaces
             $performance .= ' 'x($seq->{'width'}-$seq_max-              $performance .= ' 'x($seq->{'width'}-$seq_max-
Line 437  sub html_outputstudent { Line 545  sub html_outputstudent {
     $Str .= " \n";      $Str .= " \n";
     $r->print($Str);      $r->print($Str);
     #      #
     $count++;  
     if($count % 5 == 0) {  
         $r->print("</pre><pre>");  
     }  
     #  
     $r->rflush();      $r->rflush();
     return;      return;
 }      }    
Line 460  sub html_finish { Line 563  sub html_finish {
   
 =pod  =pod
   
   =head2 Multi-Sheet EXCEL subroutines
   
   =item &multi_sheet_excel_initialize($r)
   
   =item &multi_sheet_excel_outputstudent($r,$student)
   
   =item &multi_sheet_excel_finish($r)
   
   =cut
   
   #######################################################
   #######################################################
   {
   
   sub multi_sheet_excel_initialize {
       my ($r)=@_;
       $r->print("<h1>Not yet implemented</h1>");
       # 
       # Estimate the size of the file.  We would like to have < 5 megs of data.
       my $max_size = 5000000;
       my $num_students  = scalar(@Apache::lonstatistics::Students);
       my $num_sequences = 0;
       my $num_data_per_part  = 2; # 'status' and 'numtries'
       my $fields_per_student = scalar(&get_student_fields_to_show());
       my $bytes_per_field    = 20; # Back of the envelope calculation
       foreach my $seq (&get_sequences_to_show) {
           $num_sequences++ if ($seq->{'num_assess'} > 0);
           $fields_per_student += $num_data_per_part * $seq->{'num_assess_parts'};
       }
       my $size_estimate = $fields_per_student*$num_students*$bytes_per_field;
       #
       # Compute number of workbooks
       my $num_workbooks = 1;
       if ($size_estimate > $max_size) { # try to stay under 5 megs
           $num_workbooks += int($size_estimate / $max_size);
       }
       if ($show eq 'by section') {
           if (@Apache::lonstatistics::SelectedSections > 1 && 
               $Apache::lonstatistics::SelectedSections[0] ne 'all') {
               $num_workbooks = scalar(@Apache::lonstatistics::SelectedSections);
           } else {
               # @Apache::lonstatistics::Sections contains 'all' as well.
               $num_workbooks = scalar(@Apache::lonstatistics::Sections) - 1;
           }
       }
       
       $r->print("Maximum allowed size: ".$max_size." bytes<br />");
       $r->print("Number of students: ".$num_students."<br />");
       $r->print("Number of fields per student: ".$fields_per_student."<br />");
       $r->print("Total number of fields: ".($fields_per_student*$num_students).
                 "<br />");
       $r->print("Bytes per field: ".$bytes_per_field." (estimated)"."<br />");
       $r->print("Estimated size: ".$size_estimate." bytes<br />");
       $r->print("Number of workbooks: ".$num_workbooks."<br />");
       $r->rflush();
       return;
   }
   
   sub multi_sheet_excel_outputstudent {
       my ($r,$student) = @_;
   }
   
   sub multi_sheet_excel_finish {
       my ($r) = @_;
   }
   
   }
   #######################################################
   #######################################################
   
   =pod
   
 =head2 EXCEL subroutines  =head2 EXCEL subroutines
   
 =item &excel_initialize($r)  =item &excel_initialize($r)
Line 475  sub html_finish { Line 650  sub html_finish {
 {  {
   
 my $excel_sheet;  my $excel_sheet;
   my $excel_workbook;
   
   my $filename;
   my $rows_output;
   my $cols_output;
   
   my %prog_state; # progress window state
   
 sub excel_initialize {  sub excel_initialize {
     my ($r) = @_;      my ($r) = @_;
     #      #
     $r->print("<h1>Not implemented yet</h1>");      $filename = '/prtspool/'.
     return;  
     my $filename = '/prtspool/'.  
         $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.          $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
             time.'_'.rand(1000000000).'.xls';              time.'_'.rand(1000000000).'.xls';
     $excel_sheet = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);      #
     if (! defined($excel_sheet)) {      $excel_workbook = undef;
       $excel_sheet = undef;
       #
       $rows_output = 0;
       $cols_output = 0;
       #
       # Create sheet
       $excel_workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
       #
       # Check for errors
       if (! defined($excel_workbook)) {
         $r->log_error("Error creating excel spreadsheet $filename: $!");          $r->log_error("Error creating excel spreadsheet $filename: $!");
         $r->print("Problems creating new Excel file.  ".          $r->print("Problems creating new Excel file.  ".
                   "This error has been logged.  ".                    "This error has been logged.  ".
                   "Please alert your LON-CAPA administrator");                    "Please alert your LON-CAPA administrator");
         return 0;          return ;
     }      }
     #      #
     # The excel spreadsheet stores temporary data in files, then put them      # The excel spreadsheet stores temporary data in files, then put them
     # together.  If needed we should be able to disable this (memory only).      # together.  If needed we should be able to disable this (memory only).
     # The temporary directory must be specified before calling 'addworksheet'.      # The temporary directory must be specified before calling 'addworksheet'.
     # File::Temp is used to determine the temporary directory.      # File::Temp is used to determine the temporary directory.
     $excel_sheet->set_tempdir($Apache::lonnet::tmpdir);      $excel_workbook->set_tempdir($Apache::lonnet::tmpdir);
       #
       # Add a worksheet
       my $sheetname = $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
       if (length($sheetname) > 31) {
           $sheetname = substr($sheetname,0,31);
       }
       $excel_sheet = $excel_workbook->addworksheet($sheetname);
       #
       # Put the course description in the header
       $excel_sheet->write($rows_output,$cols_output++,
                      $ENV{'course.'.$ENV{'request.course.id'}.'.description'});
       $cols_output += 3;
       #
       # Put a description of the sections listed
       my $sectionstring = '';
       my @Sections = @Apache::lonstatistics::SelectedSections;
       if (scalar(@Sections) > 1) {
           if (scalar(@Sections) > 2) {
               my $last = pop(@Sections);
               $sectionstring = "Sections ".join(', ',@Sections).', and '.$last;
           } else {
               $sectionstring = "Sections ".join(' and ',@Sections);
           }
       } else {
           if ($Sections[0] eq 'all') {
               $sectionstring = "All sections";
           } else {
               $sectionstring = "Section ".$Sections[0];
           }
       }
       $excel_sheet->write($rows_output,$cols_output++,$sectionstring);
       $cols_output += scalar(@Sections);
       #
       # Put the date in there too
       $excel_sheet->write($rows_output,$cols_output++,
                           'Compiled on '.localtime(time));
       #
       $rows_output++;
       #
       # Add the student headers
       $cols_output = 0;
       foreach my $field (&get_student_fields_to_show()) {
           $excel_sheet->write($rows_output,$cols_output++,$field);
       }
       #
       # Add the Sequence Headers
       foreach my $seq (&get_sequences_to_show) {
           $excel_sheet->write($rows_output,$cols_output,$seq->{'title'});
           if ($show eq 'totals') {
               $excel_sheet->write($rows_output+1,$cols_output,'score');
               $excel_sheet->write($rows_output+1,$cols_output+1,'maximum');
               $cols_output += 2;
           } else {
               $cols_output++;
           }
       }
       #
       # Bookkeeping
       if ($show eq 'totals') {
           $rows_output += 2;
       } else {
           $rows_output += 1;
       }
       #
       # Let the user know what we are doing
       my $studentcount = scalar(@Apache::lonstatistics::Students); 
       $r->print("<h1>Compiling Excel spreadsheet for ".
                 $studentcount.' student');
       $r->print('s') if ($studentcount > 1);
       $r->print("</h1>\n");
       $r->rflush();
       #
       # Initialize progress window
       %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
           ($r,'Excel File Compilation Status',
            'Excel File Compilation Progress', $studentcount);
     #      #
     # Determine the name to give the worksheet  
 #    $excel_sheet->addworksheet();  
   
     return;      return;
 }  }
   
 sub excel_outputstudent {  sub excel_outputstudent {
     my ($r,$student) = @_;      my ($r,$student) = @_;
       return if (! defined($excel_sheet));
       $cols_output=0;
       #
       # Write out student data
       my @to_show = &get_student_fields_to_show();
       foreach my $field (@to_show) {
           $excel_sheet->write($rows_output,$cols_output++,$student->{$field});
       }
       #
       # Get student assessment data
       my %StudentsData;
       my @tmp = &Apache::loncoursedata::get_current_state($student->{'username'},
                                                           $student->{'domain'},
                                                           undef,
                                                      $ENV{'request.course.id'});
       if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) {
           %StudentsData = @tmp;
       }
       #
       # Write out sequence scores and totals data
       foreach my $seq (&get_sequences_to_show) {
           my ($performance,$score,$seq_max) =
               &StudentPerformanceOnSequence($student,\%StudentsData,
                                             $seq,'no');
           if ($show eq 'totals' || $show eq 'scores') {
               $excel_sheet->write($rows_output,$cols_output++,$score);
           }
           if ($show eq 'totals') {
               $excel_sheet->write($rows_output,$cols_output++,$seq_max);
           }
       }
       #
       # Bookkeeping
       $rows_output++; 
       $cols_output=0;
       #
       # Update the progress window
       &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last student');
       return;
 }  }
   
 sub excel_finish {  sub excel_finish {
     my ($r) = @_;      my ($r) = @_;
       return if (! defined($excel_sheet));
       #
       # Write the excel file
       $excel_workbook->close();
       my $c = $r->connection();
       #
       return if($c->aborted());
       #
       # Close the progress window
       &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
       #
       # Tell the user where to get their excel file
       $r->print('<br />'.
                 '<a href="'.$filename.'">Your Excel spreadsheet.</a>'."\n");
       $r->rflush();
       return;
 }  }
   
 }  }
Line 575  Inputs: Line 893  Inputs:
 #######################################################  #######################################################
 #######################################################  #######################################################
 sub StudentPerformanceOnSequence {  sub StudentPerformanceOnSequence {
     my ($student,$studentdata,$seq,$links,$totalonly) = @_;      my ($student,$studentdata,$seq,$links) = @_;
     $totalonly = 0 if (! defined($totalonly));  
     $links = 'no' if (! defined($links));      $links = 'no' if (! defined($links));
     my $Str = '';      my $Str = '';
     my ($sum,$max) = (0,0);      my ($sum,$max) = (0,0);

Removed from v.1.31  
changed lines
  Added in v.1.36


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>