--- loncom/interface/statistics/lonstudentassessment.pm 2003/06/10 15:42:51 1.54
+++ loncom/interface/statistics/lonstudentassessment.pm 2004/02/10 16:47:25 1.84
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonstudentassessment.pm,v 1.54 2003/06/10 15:42:51 matthew Exp $
+# $Id: lonstudentassessment.pm,v 1.84 2004/02/10 16:47:25 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -52,9 +52,12 @@ package Apache::lonstudentassessment;
use strict;
use Apache::lonstatistics;
use Apache::lonhtmlcommon;
+use Apache::loncommon();
use Apache::loncoursedata;
use Apache::lonnet; # for logging porpoises
+use Apache::lonlocal;
use Spreadsheet::WriteExcel;
+use Spreadsheet::WriteExcel::Utility();
#######################################################
#######################################################
@@ -138,8 +141,32 @@ Inputs:
#######################################################
sub BuildStudentAssessmentPage {
my ($r,$c)=@_;
+ #
undef($Statistics);
+ undef($show_links);
+ undef($output_mode);
+ undef($data);
+ undef($base);
+ undef($datadescription);
+ undef($single_student_mode);
+ #
+ my %Saveable_Parameters = ('Status' => 'scalar',
+ 'chartoutputmode' => 'scalar',
+ 'chartoutputdata' => 'scalar',
+ 'Section' => 'array',
+ 'StudentData' => 'array',
+ 'Maps' => 'array');
+ &Apache::loncommon::store_course_settings('chart',\%Saveable_Parameters);
+ &Apache::loncommon::restore_course_settings('chart',\%Saveable_Parameters);
+ #
+ &Apache::lonstatistics::PrepareClasslist();
+ #
+ $single_student_mode = 0;
$single_student_mode = 1 if ($ENV{'form.SelectedStudent'});
+ if ($ENV{'form.selectstudent'}) {
+ &Apache::lonstatistics::DisplayClasslist($r);
+ return;
+ }
#
# Print out the HTML headers for the interface
# This also parses the output mode selector
@@ -149,16 +176,8 @@ sub BuildStudentAssessmentPage {
$r->print(' ');
$r->rflush();
+ #
if (! exists($ENV{'form.notfirstrun'}) && ! $single_student_mode) {
- $r->print(<
-
-Please make your selections in the boxes above and hit
-the button marked "Update Display".
-
-
-ENDMSG
-# $r->print(&OutputDescriptions());
return;
}
#
@@ -188,6 +207,16 @@ ENDMSG
@Students = @Apache::lonstatistics::Students;
}
#
+ # Perform generic initialization tasks
+ # Since we use lonnet::EXT to retrieve problem weights,
+ # to ensure current data we must clear the caches out.
+ # This makes sure that parameter changes at the student level
+ # are immediately reflected in the chart.
+ &Apache::lonnet::clear_EXT_cache_status();
+ #
+ # Clean out loncoursedata's package data, just to be safe.
+ &Apache::loncoursedata::clear_internal_caches();
+ #
# Call the initialize routine selected above
$initialize->($r);
foreach my $student (@Students) {
@@ -290,12 +319,16 @@ sub CreateInterface {
# $Str .= &CreateLegend();
$Str .= ''."\n";
$Str .= '';
- $Str .= 'Sections ';
- $Str .= 'Student Data ';
- $Str .= 'Enrollment Status ';
- $Str .= 'Sequences and Folders ';
- $Str .= 'Output Format ';
- $Str .= 'Output Data ';
+ $Str .= ''.&mt('Sections').' ';
+ $Str .= ''.&mt('Student Data ').' ';
+ $Str .= ''.&mt('Enrollment Status').' ';
+ $Str .= ''.&mt('Sequences and Folders').' ';
+ $Str .= ''.&mt('Output Format').' '.
+ &Apache::loncommon::help_open_topic("Chart_Output_Formats").
+ ' ';
+ $Str .= ''.&mt('Output Data').' '.
+ &Apache::loncommon::help_open_topic("Chart_Output_Data").
+ ' ';
$Str .= ' '."\n";
#
$Str .= ''."\n";
@@ -322,6 +355,16 @@ sub CreateInterface {
$Str .= &CreateAndParseOutputDataSelector();
$Str .= ' '."\n";
$Str .= '
'."\n";
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
return $Str;
}
@@ -366,29 +409,12 @@ my @OutputOptions =
mode => 'excel',
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_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_links => 'no',
-# },
{ name => 'CSV',
value => 'csv',
description => 'Output a comma seperated values file suitable for '.
- 'import into a spreadsheet.',
+ 'import into a spreadsheet program. Using this method as opposed '.
+ 'to Excel output allows you to organize your data before importing'.
+ ' it into a spreadsheet program.',
mode => 'csv',
show_links => 'no',
},
@@ -396,7 +422,7 @@ my @OutputOptions =
sub OutputDescriptions {
my $Str = '';
- $Str .= "Output Modes \n";
+ $Str .= "Output Formats \n";
$Str .= "\n";
foreach my $outputmode (@OutputOptions) {
$Str .=" ".$outputmode->{'name'}." \n";
@@ -409,6 +435,8 @@ sub OutputDescriptions {
sub CreateAndParseOutputSelector {
my $Str = '';
my $elementname = 'chartoutputmode';
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+ [$elementname]);
#
# Format for output options is 'mode, restrictions';
my $selected = 'html, without links';
@@ -435,7 +463,7 @@ sub CreateAndParseOutputSelector {
foreach my $option (@OutputOptions) {
$Str .= "\n".' {'value'} eq $selected);
- $Str .= ">".$option->{'name'}."<\/option>";
+ $Str .= ">".&mt($option->{'name'})."<\/option>";
}
$Str .= "\n";
return $Str;
@@ -445,61 +473,76 @@ sub CreateAndParseOutputSelector {
## Data selector stuff
##
my @OutputDataOptions =
- ( { name =>'Tries',
- base =>'tries',
- value => 'tries',
- shortdesc => 'Number of Tries before success on each Problem Part',
- longdesc =>'The number of tries before success on each problem part.',
- },
- { name =>'Parts Correct',
- base =>'tries',
- value => 'parts correct',
- shortdesc => 'Number of Problem Parts completed successfully.',
- longdesc => 'The Number of Problem Parts completed successfully.',
- },
- { name =>'Parts Correct & Maximums',
- base =>'tries',
- value => 'parts correct total',
- shortdesc => 'Number of Problem Parts completed successfully.',
- longdesc => 'The Number of Problem Parts completed successfully and '.
- 'the maximum possible for each student',
- },
- { name => 'Scores',
- base => 'scores',
- value => 'scores',
- shortdesc => 'Score on each Problem Part',
- longdesc =>'The students score on each problem part, computed as'.
- 'the part weight * part awarded',
- },
- { name => 'Scores Sum',
- base => 'scores',
- value => 'sum only',
- shortdesc => 'Sum of Scores on each Problem Part',
- longdesc =>'The total of the scores of the student on each problem'.
- ' part in the sequences or folders selected.',
- },
- { name => 'Scores Sum & Maximums',
- base => 'scores',
- value => 'sum and total',
- shortdesc => 'Total Score and Maximum Possible for each '.
- 'Sequence or Folder',
- longdesc => 'The total of the scores of the student on each problem'.
- ' and the maximum possible for that student on each Sequence or '.
- ' Folder.',
- },
- { name => 'Summary Table (Scores)',
- base => 'scores',
- value => 'final table scores',
- shortdesc => 'Summary of Scores',
- longdesc => '',
- },
- { name => 'Summary Table (Parts)',
- base => 'tries',
- value => 'final table parts',
- shortdesc => 'Summary of Parts Correct',
- longdesc => '',
- }
- );
+ (
+ { name => 'Scores Summary',
+ base => 'scores',
+ value => 'sum and total',
+ shortdesc => 'Total Score and Maximum Possible for each '.
+ 'Sequence or Folder',
+ longdesc => 'The score of each student as well as the '.
+ ' maximum possible on each Sequence or Folder.',
+ },
+ { name => 'Scores Per Problem',
+ base => 'scores',
+ value => 'scores',
+ shortdesc => 'Score on each Problem Part',
+ longdesc =>'The students score on each problem part, computed as'.
+ 'the part weight * part awarded',
+ },
+# { name => 'Scores Sum',
+# base => 'scores',
+# value => 'sum only',
+# shortdesc => 'Sum of Scores on each Problem Part',
+# longdesc =>'The total of the scores of the student on each problem'.
+# ' part in the sequences or folders selected.',
+# },
+# { name => 'Scores Summary Table Only',
+# base => 'scores',
+# value => 'final table scores',
+# shortdesc => 'Summary of Scores',
+# longdesc => 'The average score on each sequence or folder for the '.
+# 'selected students.',
+# },
+ { name =>'Tries',
+ base =>'tries',
+ value => 'tries',
+ shortdesc => 'Number of Tries before success on each Problem Part',
+ longdesc =>'The number of tries before success on each problem part.',
+ },
+ { name =>'Parts Correct',
+ base =>'tries',
+ value => 'parts correct total',
+ shortdesc => 'Number of Problem Parts completed successfully.',
+ longdesc => 'The Number of Problem Parts completed successfully and '.
+ 'the maximum possible for each student',
+ },
+# { name =>'Parts Correct',
+# base =>'tries',
+# value => 'parts correct',
+# shortdesc => 'Number of Problem Parts completed successfully.',
+# longdesc => 'The Number of Problem Parts completed successfully'.
+# ' on each sequence or folder.',
+# },
+# { name => 'Parts Summary Table Only',
+# base => 'tries',
+# value => 'final table parts',
+# shortdesc => 'Summary of Parts Correct',
+# longdesc => 'A summary table of the average number of problem parts '.
+# 'students were able to get correct on each sequence.',
+# },
+ );
+
+sub HTMLifyOutputDataDescriptions {
+ my $Str = '';
+ $Str .= "Output Data \n";
+ $Str .= "\n";
+ foreach my $option (@OutputDataOptions) {
+ $Str .= ' '.$option->{'name'}.' ';
+ $Str .= ''.$option->{'longdesc'}.' '."\n";
+ }
+ $Str .= " \n";
+ return $Str;
+}
sub CreateAndParseOutputDataSelector {
my $Str = '';
@@ -528,7 +571,7 @@ sub CreateAndParseOutputDataSelector {
foreach my $option (@OutputDataOptions) {
$Str .= "\n".' {'value'} eq $data);
- $Str .= ">".$option->{'name'}."<\/option>";
+ $Str .= ">".&mt($option->{'name'})."<\/option>";
}
$Str .= "\n";
return $Str;
@@ -569,11 +612,14 @@ sub html_initialize {
$padding = ' 'x3;
$count = 0;
$nodata_count = 0;
+ undef(%prog_state);
#
$r->print("".$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
" ".localtime(time)." ");
- $r->print("".$datadescription." ");
+ if ($data !~ /^final table/) {
+ $r->print("".$datadescription." ");
+ }
#
# Set up progress window for 'final table' display only
if ($data =~ /^final table/) {
@@ -614,7 +660,7 @@ sub html_outputstudent {
my ($r,$student) = @_;
my $Str = '';
#
- if($count++ % 5 == 0 && $count > 0) {
+ if($count++ % 5 == 0 && $count > 0 && $data !~ /^final table/) {
$r->print("");
}
# First, the @StudentData fields need to be listed
@@ -739,22 +785,20 @@ sub StudentAverageTotal {
$total_ave += $ave;
my $max = $Statistics->{$seq->{'symb'}}->{'max'};
$total_max += $max;
- if ($ave == 0) {
- $ave = "0.00";
- }
- $ave .= ' ';
- $max .= ' ';
+ $ave = sprintf("%.2f",$ave);
$Str .= ''.$seq->{'title'}.' '.
- ''.$ave.' '.
- ''.$max.' '."\n";
+ ''.$ave.' '.
+ ''.$max.' '.' '."\n";
}
- $total_ave = int(100*$total_ave)/100; # only two digit
+ $total_ave = sprintf('%.2f',$total_ave); # only two digit
$Str .= "\n";
$Str .= ' '."\n";
$Str .= 'Number of Students Average '.
"Maximum \n";
- $Str .= ''.($num_students-$nodata_count).' '.
- ''.$total_ave.' '.$total_max.' ';
+ $Str .= ''.
+ ''.($num_students-$nodata_count).' '.
+ ''.$total_ave.' '.' '.
+ ''.$total_max.' '.' ';
$Str .= "
\n";
return $Str;
}
@@ -791,78 +835,6 @@ sub SingleStudentTotal {
=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("Not yet implemented ");
- #
- # 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 (&Apache::lonstatistics::Sequences_with_Assess()) {
- $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 ($data eq ) {
-# 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 ");
- $r->print("Number of students: ".$num_students." ");
- $r->print("Number of fields per student: ".$fields_per_student." ");
- $r->print("Total number of fields: ".($fields_per_student*$num_students).
- " ");
- $r->print("Bytes per field: ".$bytes_per_field." (estimated)"." ");
- $r->print("Estimated size: ".$size_estimate." bytes ");
- $r->print("Number of workbooks: ".$num_workbooks." ");
- $r->rflush();
- return;
-}
-
-sub multi_sheet_excel_outputstudent {
- my ($r,$student) = @_;
-}
-
-sub multi_sheet_excel_finish {
- my ($r) = @_;
-}
-
-}
-#######################################################
-#######################################################
-
-=pod
-
=head2 EXCEL subroutines
=item &excel_initialize($r)
@@ -887,10 +859,20 @@ my $cols_output;
my %prog_state; # progress window state
my $request_aborted;
+my $total_formula;
+
sub excel_initialize {
my ($r) = @_;
#
- $request_aborted = undef;
+ undef ($excel_sheet);
+ undef ($excel_workbook);
+ undef ($filename);
+ undef ($rows_output);
+ undef ($cols_output);
+ undef (%prog_state);
+ undef ($request_aborted);
+ undef ($total_formula);
+ #
my $total_columns = scalar(&get_student_fields_to_show());
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
# Add 2 because we need a 'sum' and 'total' column for each
@@ -925,7 +907,7 @@ You may consider reducing the number of
have selected.
LON-CAPA can produce CSV files of this data or Excel files of the
-summary data (Scores Sum or Scores Sum & Totals ).
+Scores Summary data.
END
$request_aborted = 1;
@@ -971,9 +953,7 @@ END
#
# Add a worksheet
my $sheetname = $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
- if (length($sheetname) > 31) {
- $sheetname = substr($sheetname,0,31);
- }
+ $sheetname = &Apache::loncommon::clean_excel_name($sheetname);
$excel_sheet = $excel_workbook->addworksheet($sheetname);
#
# Put the course description in the header
@@ -1023,12 +1003,25 @@ END
}
#
# Add the remaining column headers
+ my $total_formula_string = '=0';
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
$excel_sheet->write($rows_output+$row_offset,
$cols_output,$seq->{'title'});
if ($data eq 'tries' || $data eq 'scores') {
+ # Determine starting cell
+ $seq->{'Excel:startcell'}=
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$cols_output);
+ $seq->{'Excel:startcol'}=$cols_output;
+ # Put the names of the problems and parts into the sheet
+ my $count = 0;
foreach my $res (@{$seq->{'contents'}}) {
- next if ($res->{'type'} ne 'assessment');
+ if ($res->{'type'} ne 'assessment' ||
+ ! exists($res->{'parts'}) ||
+ ref($res->{'parts'}) ne 'ARRAY' ||
+ scalar(@{$res->{'parts'}}) < 1) {
+ next;
+ }
if (scalar(@{$res->{'parts'}}) > 1) {
foreach my $part (@{$res->{'parts'}}) {
$excel_sheet->write($rows_output,
@@ -1040,17 +1033,45 @@ END
$cols_output++,
$res->{'title'});
}
+ $count++;
}
- $excel_sheet->write($rows_output,$cols_output++,'score');
- $excel_sheet->write($rows_output,$cols_output++,'maximum');
- } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
- $excel_sheet->write($rows_output+1,$cols_output,'score');
- $excel_sheet->write($rows_output+1,$cols_output+1,'maximum');
- $cols_output += 2;
+ # Determine ending cell
+ if ($count == 1) {
+ $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
+ $seq->{'Excel:endcol'} = $seq->{'Excel:startcol'};
+ } else {
+ $seq->{'Excel:endcell'} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$cols_output-1);
+ $seq->{'Excel:endcol'} = $cols_output-1;
+ }
+ # Create the formula for summing up this sequence
+ if (! exists($seq->{'Excel:endcell'}) ||
+ ! defined($seq->{'Excel:endcell'})) {
+ $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
+ }
+ $seq->{'Excel:sum'}= $excel_sheet->store_formula
+ ('=SUM('.$seq->{'Excel:startcell'}.
+ ':'.$seq->{'Excel:endcell'}.')');
+ }
+ # Determine cell the score is held in
+ $seq->{'Excel:scorecell'} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$cols_output);
+ $seq->{'Excel:scorecol'}=$cols_output;
+ if ($data eq 'parts correct total') {
+ $excel_sheet->write($rows_output,$cols_output++,'parts correct');
} else {
- $cols_output++;
+ $excel_sheet->write($rows_output,$cols_output++,'score');
}
+ #
+ $total_formula_string.='+'.
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$cols_output-1);
+ $excel_sheet->write($rows_output,$cols_output++,'maximum');
}
+ $excel_sheet->write($rows_output,$cols_output++,'Grand Total');
+ $total_formula = $excel_sheet->store_formula($total_formula_string);
#
# Bookkeeping
if ($data eq 'sum and total' || $data eq 'parts correct total') {
@@ -1071,7 +1092,12 @@ END
}
#
# Add the maximums for each sequence or assessment
+ my %total_cell_translation;
+ my $grand_total = 0;
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ $total_cell_translation{$seq->{'Excel:scorecell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:scorecol'});
my $weight;
my $max = 0;
foreach my $resource (@{$seq->{'contents'}}) {
@@ -1097,7 +1123,30 @@ END
if (! ($data eq 'sum only' || $data eq 'parts correct')) {
$excel_sheet->write($rows_output,$cols_output++,'');
}
- $excel_sheet->write($rows_output,$cols_output++,$max);
+ #
+ if ($data eq 'tries' || $data eq 'scores') {
+ my %replaceCells;
+ $replaceCells{$seq->{'Excel:startcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:startcol'});
+ $replaceCells{$seq->{'Excel:endcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:endcol'});
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells);
+ } else {
+ $excel_sheet->write($rows_output,$cols_output++,
+ $max);
+ }
+ $grand_total+=$max;
+ }
+ if ($data eq 'tries' || $data eq 'scores') {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $total_formula,undef,
+ %total_cell_translation);
+ } else {
+ $excel_sheet->write($rows_output,$cols_output++,$grand_total);
}
$rows_output++;
#
@@ -1114,6 +1163,8 @@ END
($r,'Excel File Compilation Status',
'Excel File Compilation Progress', $studentcount);
#
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
+ 'Processing first student');
return;
}
@@ -1140,7 +1191,13 @@ sub excel_outputstudent {
}
#
# Write out sequence scores and totals data
+ my %total_cell_translation;
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ # Keep track of cells to translate in total cell
+ $total_cell_translation{$seq->{'Excel:scorecell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:scorecol'});
+ #
my ($performance,$performance_length,$score,$seq_max,$rawdata);
if ($base eq 'tries') {
($performance,$performance_length,$score,$seq_max,$rawdata) =
@@ -1155,7 +1212,25 @@ sub excel_outputstudent {
foreach my $value (@$rawdata) {
$excel_sheet->write($rows_output,$cols_output++,$value);
}
- $excel_sheet->write($rows_output,$cols_output++,$score);
+ # Write a formula for the sum of this sequence
+ my %replaceCells;
+ $replaceCells{$seq->{'Excel:startcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:startcol'});
+ $replaceCells{$seq->{'Excel:endcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:endcol'});
+ # The undef is for the format
+ if (scalar(keys(%replaceCells)) == 1) {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells,%replaceCells);
+ } else {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells);
+ }
+ #
$excel_sheet->write($rows_output,$cols_output++,$seq_max);
} elsif ($data eq 'sum and total' || $data eq 'sum only' ||
$data eq 'parts correct' || $data eq 'parts correct total') {
@@ -1166,6 +1241,11 @@ sub excel_outputstudent {
}
}
#
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $total_formula,undef,
+ %total_cell_translation);
+
+ #
# Bookkeeping
$rows_output++;
$cols_output=0;
@@ -1225,8 +1305,9 @@ sub csv_initialize{
my ($r) = @_;
#
# Clean up
- $filename = undef;
- $outputfile = undef;
+ undef($outputfile);
+ undef($filename);
+ undef($request_aborted);
undef(%prog_state);
#
# Deal with unimplemented requests
@@ -1430,43 +1511,56 @@ sub StudentTriesOnSequence {
$performance_length++;
my $symbol = ' '; # default to space
#
+ my $awarded = 0;
+ if (exists($resource_data->{'resource.'.$partnum.'.awarded'})) {
+ $awarded = $resource_data->{'resource.'.$partnum.'.awarded'};
+ $awarded = 0 if (! $awarded);
+ }
+ #
+ my $status = '';
if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {
- my $status = $resource_data->{'resource.'.$partnum.'.solved'};
- if ($status eq 'correct_by_override') {
- $symbol = '+';
- $sum++;
- } elsif ($status eq 'incorrect_by_override') {
- $symbol = '-';
- } elsif ($status eq 'ungraded_attempted') {
- $symbol = '#';
- } elsif ($status eq 'incorrect_attempted') {
- $symbol = '.';
- } elsif ($status eq 'excused') {
+ $status = $resource_data->{'resource.'.$partnum.'.solved'};
+ }
+ #
+ my $tries = 0;
+ if(exists($resource_data->{'resource.'.$partnum.'.tries'})) {
+ $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ }
+ #
+ if ($awarded > 0) {
+ # The student has gotten the problem correct to some degree
+ if ($status eq 'excused') {
$symbol = 'x';
$max--;
- } elsif ($status eq 'correct_by_student' &&
- exists($resource_data->{'resource.'.$partnum.'.tries'})){
- $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ } elsif ($status eq 'correct_by_override') {
+ $symbol = '+';
+ $sum++;
+ } elsif ($tries > 0) {
if ($tries > 9) {
$symbol = '*';
- } elsif ($tries > 0) {
- $symbol = $tries;
} else {
- $symbol = ' ';
+ $symbol = $tries;
}
$sum++;
- } elsif (exists($resource_data->{'resource.'.
- $partnum.'.tries'})){
- $symbol = '.';
} else {
- $symbol = ' ';
+ $symbol = '+';
+ $sum++;
}
} else {
- # Unsolved. Did they try?
- if (exists($resource_data->{'resource.'.$partnum.'.tries'})){
+ # The student has the problem incorrect or it is ungraded
+ if ($status eq 'excused') {
+ $symbol = 'x';
+ $max--;
+ } elsif ($status eq 'incorrect_by_override') {
+ $symbol = '-';
+ } elsif ($status eq 'ungraded_attempted') {
+ $symbol = '#';
+ } elsif ($status eq 'incorrect_attempted' ||
+ $tries > 0) {
$symbol = '.';
} else {
- $symbol = ' ';
+ # Problem is wrong and has not been attempted.
+ $symbol=' ';
}
}
#
@@ -1483,7 +1577,7 @@ sub StudentTriesOnSequence {
$symbol = ''.$symbol.' ';
}
$value .= $symbol;
@@ -1551,11 +1645,15 @@ sub StudentPerformanceOnSequence {
my $awarded = 0;
if (exists($resource_data->{'resource.'.$part.'.awarded'})) {
$awarded = $resource_data->{'resource.'.$part.'.awarded'};
+ $awarded = 0 if (! $awarded);
}
#
$partscore = $weight*$awarded;
$score += $partscore;
- $symbol = $weight;
+ $symbol = $partscore;
+ if (abs($symbol - sprintf("%.0f",$symbol)) < 0.001) {
+ $symbol = sprintf("%.0f",$symbol);
+ }
if (length($symbol) > 1) {
$symbol = '*';
}
@@ -1574,19 +1672,20 @@ sub StudentPerformanceOnSequence {
}
}
#
+ if (! defined($partscore)) {
+ $partscore = $symbol;
+ }
+ push (@ScoreData,$partscore);
+ #
if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
$symbol = ''.$symbol.' ';
}
- if (! defined($partscore)) {
- $partscore = $symbol;
- }
- push (@ScoreData,$partscore);
+ $Str .= $symbol;
}
- $Str .= $symbol;
}
return ($Str,$performance_length,$score,$max,\@ScoreData);
}