--- loncom/interface/statistics/lonproblemstatistics.pm 2003/03/25 23:00:40 1.41 +++ loncom/interface/statistics/lonproblemstatistics.pm 2003/03/26 17:03:41 1.44 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonproblemstatistics.pm,v 1.41 2003/03/25 23:00:40 matthew Exp $ +# $Id: lonproblemstatistics.pm,v 1.44 2003/03/26 17:03:41 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -35,6 +35,7 @@ use Apache::lonnet(); use Apache::lonhtmlcommon; use Apache::loncoursedata; use Apache::lonstatistics; +use Spreadsheet::WriteExcel; ####################################################### ####################################################### @@ -229,12 +230,20 @@ sub BuildProblemStatisticsPage { } elsif ($show eq 'ungrouped') { &output_html_ungrouped($r); } + } elsif ($output_mode eq 'excel') { + $r->print("

Preparing Excel Spreadsheet

"); + &output_excel($r); } else { $r->print("

Not implemented

"); } return; } +############################################### +############################################### + +############################################### +############################################### sub output_html_grouped_by_sequence { my ($r) = @_; #$r->print(&ProblemStatisticsLegend()); @@ -243,6 +252,7 @@ sub output_html_grouped_by_sequence { "S.D.","Skew.");#,"D.F.1st","D.F.2nd"); # #FFFFE6 #EEFFCC #DDFFFF FFDDDD #DDFFDD #FFDDFF foreach my $sequence (&Apache::lonstatistics::Sequences_with_Assess()) { + my $show_part = 0; next if ($sequence->{'num_assess'}<1); $r->print("

".$sequence->{'title'}."

"); $r->print(''.&statistics_html_table_data ($resource,$part,$num,$tries,$mod,$mean,$Solved, - $solved,$wrongpercent,$DegOfDiff,$STD,$SKEW). + $solved,$wrongpercent,$DegOfDiff,$STD,$SKEW, + $show_part). "\n"); } } @@ -277,7 +289,6 @@ sub output_html_grouped_by_sequence { return; } - ############################################### ############################################### @@ -286,16 +297,22 @@ sub output_html_grouped_by_sequence { sub output_html_ungrouped { my ($r) = @_; # - my $sortby = $ENV{'form.sortby'}; - if (! defined($sortby) || $sortby eq '') { - $sortby = 'sequence'; - } - # my $show_container = 0; + my $show_part = 0; #$r->print(&ProblemStatisticsLegend()); my @Header = ("Title","Part","#Stdnts","Tries","Mod", "Mean","#YES","#yes","%Wrng","DoDiff", - "S.D.","Skew.");#,"D.F.1st","D.F.2nd"); + "S.D.","Skew");#,"D.F.1st","D.F.2nd"); + # + my $sortby = undef; + foreach (@Header) { + if ($ENV{'form.sortby'} eq $_) { + $sortby = $_; + } + } + if (! defined($sortby) || $sortby eq '') { + $sortby = 'Container'; + } # #FFFFE6 #EEFFCC #DDFFFF FFDDDD #DDFFDD #FFDDFF my @Sequences = &Apache::lonstatistics::Sequences_with_Assess(); if (@Sequences > 1) { @@ -304,71 +321,261 @@ sub output_html_ungrouped { } # $r->print('
'."\n"); @@ -252,20 +262,22 @@ sub output_html_grouped_by_sequence { foreach my $resource (@{$sequence->{'contents'}}) { next if ($resource->{'type'} ne 'assessment'); foreach my $part (@{$resource->{'parts'}}) { - if ($part == 0) { - $part = ' '; - } my ($num,$tries,$mod,$mean,$Solved,$solved,$DegOfDiff,$STD, $SKEW) = &Apache::loncoursedata::get_problem_statistics (undef,$resource->{'symb'},$part, $ENV{'request.course.id'}); + # + $show_part = 1 if ($part ne '0'); + $part = ' ' if ($part == 0); + # my $wrongpercent = 0; if (defined($num) && $num > 0) { $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10; } $r->print('
'."\n"); + $r->rflush(); + # + # Compile the data + my @Statsarray; + foreach my $sequence (@Sequences) { + next if ($sequence->{'num_assess'}<1); + foreach my $resource (@{$sequence->{'contents'}}) { + next if ($resource->{'type'} ne 'assessment'); + foreach my $part (@{$resource->{'parts'}}) { + my ($num,$tries,$mod,$mean,$Solved,$solved,$DegOfDiff,$STD, + $SKEW) = &Apache::loncoursedata::get_problem_statistics + (undef,$resource->{'symb'},$part, + $ENV{'request.course.id'}); + # + $show_part = 1 if ($part ne '0'); + $part = ' ' if ($part == 0); + # + my $wrongpercent = 0; + if (defined($num) && $num > 0) { + $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10; + } + push (@Statsarray, + { 'sequence' => $sequence, + 'resource' => $resource, + 'Title' => $resource->{'title'}, + 'Part' => $part, + '#Stdnts' => $num, + 'Tries' => $tries, + 'Mod' => $mod, + 'Mean' => $mean, + '#YES' => $Solved, + '#yes' => $solved, + '%Wrng' => $wrongpercent, + 'DoDiff' => $DegOfDiff, + 'S.D.' => $STD, + 'Skew' => $SKEW, + }); + } + } + } + # + # Table Headers $r->print(''."\n"); my $Str = ''; foreach (@Header) { - $Str .= ''; + } else { + $Str .= ''; + $_.''; + } } $r->print(''.$Str."\n"); + # + # Sort the data + my @OutputOrder; + if ($sortby eq 'Container') { + @OutputOrder = @Statsarray; + } else { + # $sortby is already defined, so we can charge ahead + if ($sortby =~ /^(title|part)$/i) { + # Alpha comparison + @OutputOrder = sort { + lc($a->{$sortby}) cmp lc($b->{$sortby}) || + lc($a->{'Title'}) cmp lc($b->{'Title'}) || + lc($a->{'Part'}) cmp lc($b->{'Part'}); + } @Statsarray; + } else { + # Numerical comparison + @OutputOrder = sort { + my $retvalue = 0; + if ($b->{$sortby} eq 'nan') { + if ($a->{$sortby} ne 'nan') { + $retvalue = -1; + } else { + $retvalue = 0; + } + } + if ($a->{$sortby} eq 'nan') { + if ($b->{$sortby} ne 'nan') { + $retvalue = 1; + } + } + if ($retvalue eq '0') { + $retvalue = $b->{$sortby} <=> $a->{$sortby} || + lc($a->{'Title'}) <=> lc($b->{'Title'}) || + lc($a->{'Part'}) <=> lc($b->{'Part'}); + } + $retvalue; + } @Statsarray; + } + } + foreach my $row (@OutputOrder) { + $r->print(''); + if ($show_container) { + $r->print(''); + } + $r->print(&stats_row_from_hash($row,$show_part)); + $r->print("\n"); + } + $r->print("
'. + next if ($_ eq 'Part' && !$show_part); + # Do not allow sorting on some fields + if ($_ eq $sortby || /^(Part)$/) { + $Str .= ''.$_.''. ''. - $_.'
' + .$row->{'sequence'}->{'title'}.'
\n"); + $r->print("
\n"); $r->rflush(); # - foreach my $sequence (@Sequences) { + return; +} + +sub stats_row_from_hash { + my ($data,$show_part) = @_; + return &statistics_html_table_data($data->{'resource'},$data->{'Part'}, + $data->{'#Stdnts'}, $data->{'Tries'}, + $data->{'Mod'}, $data->{'Mean'}, + $data->{'#YES'}, $data->{'#yes'}, + $data->{"\%Wrng"}, $data->{'DoDiff'}, + $data->{'S.D.'}, $data->{'Skew'}, + $show_part); +} + +############################################### +############################################### + +############################################### +############################################### +sub output_excel { + my ($r) = @_; + my $filename = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.xls'; + # + my $excel_workbook = undef; + my $excel_sheet = undef; + # + my $rows_output = 0; + my $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->print("Problems creating new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"); + return ; + } + # + # The excel spreadsheet stores temporary data in files, then put them + # together. If needed we should be able to disable this (memory only). + # The temporary directory must be specified before calling 'addworksheet'. + # File::Temp is used to determine the temporary directory. + $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++; + $cols_output=0; + # + # Add the headers + my @Header = ("Container","Title","Part","#Stdnts","Tries","Mod", + "Mean","#YES","#yes","%Wrng","DoDiff", + "S.D.","Skew.");#,"D.F.1st","D.F.2nd"); + foreach (@Header) { + $excel_sheet->write($rows_output,$cols_output++,$_); + } + $rows_output++; + # + # Write the data + foreach my $sequence (&Apache::lonstatistics::Sequences_with_Assess()) { next if ($sequence->{'num_assess'}<1); foreach my $resource (@{$sequence->{'contents'}}) { next if ($resource->{'type'} ne 'assessment'); foreach my $part (@{$resource->{'parts'}}) { + $cols_output=0; my ($num,$tries,$mod,$mean,$Solved,$solved,$DegOfDiff,$STD, $SKEW) = &Apache::loncoursedata::get_problem_statistics (undef,$resource->{'symb'},$part, $ENV{'request.course.id'}); - if ($part == 0) { - $part = ' '; + # + if (!defined($part) || $part eq '') { + $part = ' '; } my $wrongpercent = 0; if (defined($num) && $num > 0) { $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10; } - if ($show_container) { - $r->print(''. - ''.$sequence->{'title'}. - ''. - &statistics_html_table_data - ($resource,$part,$num,$tries,$mod,$mean,$Solved, - $solved,$wrongpercent,$DegOfDiff,$STD,$SKEW). - "\n"); - } else { - $r->print(''.&statistics_html_table_data - ($resource,$part,$num,$tries,$mod,$mean,$Solved, - $solved,$wrongpercent,$DegOfDiff,$STD,$SKEW). - "\n"); + foreach ($sequence->{'title'},$resource->{'title'},$part, + $num,$tries,$mod,$mean,$Solved,$solved,$wrongpercent, + $DegOfDiff,$STD,$SKEW) { + $excel_sheet->write($rows_output,$cols_output++,$_); } + $rows_output++; } } } - $r->print("\n"); - $r->print("\n"); - $r->rflush(); # + # Write the excel file + $excel_workbook->close(); + # Tell the user where to get their excel file + $r->print('
'. + 'Your Excel spreadsheet.'."\n"); + $r->rflush(); return; } -############################################### -############################################### -############################################### -############################################### + sub statistics_html_table_data { my ($resource,$part,$num,$tries,$mod,$mean,$Solved,$solved,$wrongpercent, - $DegOfDiff,$STD,$SKEW) = @_; + $DegOfDiff,$STD,$SKEW,$show_part) = @_; my $row = ''; $row .= ''. ''. $resource->{'title'}.''. ''; - $row .= ''.$part.'' if (defined($part)); + $row .= ''.$part.'' if ($show_part); foreach ($num,$tries) { $row .= ''.$_.''; }