'."\n");
- $r->print(''."\n");
- my $Str = '';
- foreach (@Header) {
- if (/^(Part)$/) { # Do not allow sorting on this field
- $Str .= ''.$_.' | ';
- } else {
- $Str .= ''.
- ''.
- $_.' | ';
- }
- }
- $r->print(''.$Str." \n");
$r->rflush();
#
# Compile the data
- my %Statshash;
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'}}) {
+ $problem_num++;
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;
}
- my $key = $resource->{'symb'}.':'.$part;
- $Statshash{$key} =
- {
- 'sequence' => $sequence,
+ push (@Statsarray,
+ { 'sequence' => $sequence,
'resource' => $resource,
'Title' => $resource->{'title'},
'Part' => $part,
@@ -357,39 +451,41 @@ sub output_html_ungrouped {
'DoDiff' => $DegOfDiff,
'S.D.' => $STD,
'Skew' => $SKEW,
- };
- push (@Statsarray,$Statshash{$key});
+ 'problem_num' => $problem_num,
+ });
}
}
}
#
+ # Table Headers
+ $r->print(''."\n");
+ my $Str = '';
+ foreach (@Header) {
+ next if ($_ eq 'Part' && !$show_part);
+ # Do not allow sorting on some fields
+ if ($_ eq $sortby || /^(Part|P\#)$/) {
+ $Str .= ''.$_.' | ';
+ } else {
+ $Str .= ''.
+ ''.
+ $_.' | ';
+ }
+ }
+ $r->print(''.$Str." \n");
+ #
# Sort the data
+ my @OutputOrder;
if ($sortby eq 'Container') {
- 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 $key = $resource->{'symb'}.':'.$part;
- $r->print('');
- if ($show_container) {
- $r->print(''
- .$sequence->{'title'}.' | ');
- }
- $r->print(&stats_row_from_hash($Statshash{$key}));
- $r->print(" \n");
- }
- }
- }
+ @OutputOrder = @Statsarray;
} else {
# $sortby is already defined, so we can charge ahead
- my @OutputOrder;
if ($sortby =~ /^(title|part)$/i) {
# Alpha comparison
@OutputOrder = sort {
- $b->{$sortby} cmp $a->{$sortby} ||
- $b->{'Title'} cmp $a->{'Title'} ||
- $b->{'Part'} cmp $a->{'Part'};
+ 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
@@ -409,21 +505,30 @@ sub output_html_ungrouped {
}
if ($retvalue eq '0') {
$retvalue = $b->{$sortby} <=> $a->{$sortby} ||
- $b->{'Title'} <=> $a->{'Title'} ||
- $b->{'Part'} <=> $a->{'Part'};
+ 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(''
- .$row->{'sequence'}->{'title'}.' | ');
- }
- $r->print(&stats_row_from_hash($row));
- $r->print(" \n");
- }
+ }
+ $option .= ',no part' if (! $show_part);
+ foreach my $row (@OutputOrder) {
+ $r->print('');
+ if (defined($option) && $option =~ /show probnum/) {
+ $r->print(''.$row->{'problem_num'}.' | ');
+ }
+ if ($show_container) {
+ $r->print(''
+ .$row->{'sequence'}->{'title'}.' | ');
+ }
+ $r->print(&statistics_html_table_data
+ ($row->{'resource'},$row->{'Part'},$row->{'#Stdnts'},
+ $row->{'Tries'},$row->{'Mod'},$row->{'Mean'},
+ $row->{'#YES'},$row->{'#yes'},$row->{"\%Wrng"},
+ $row->{'DoDiff'},$row->{'S.D.'},$row->{'Skew'},
+ $option));
+ $r->print(" \n");
}
$r->print(" \n");
$r->print(" \n");
@@ -432,38 +537,164 @@ sub output_html_ungrouped {
return;
}
-sub stats_row_from_hash {
- my ($data) = @_;
- if (ref($data) ne 'HASH') {
- my %Tmp = @_;
- $data = \%Tmp;
- }
- 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'});
+###############################################
+###############################################
+
+=pod
+
+=item &output_excel()
+
+Presents the statistical data in an Excel 95 compatable spreadsheet file.
+
+=cut
+
+###############################################
+###############################################
+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 (!defined($part) || $part eq '') {
+ $part = ' ';
+ }
+ my $wrongpercent = 0;
+ if (defined($num) && $num > 0) {
+ $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10;
+ }
+ 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++;
+ }
+ }
+ }
+ #
+ # 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;
}
###############################################
###############################################
+=pod
+
+=item &statistics_html_table_data()
+
+Help function used to format the rows for HTML table output.
+
+=cut
+
###############################################
###############################################
sub statistics_html_table_data {
my ($resource,$part,$num,$tries,$mod,$mean,$Solved,$solved,$wrongpercent,
- $DegOfDiff,$STD,$SKEW) = @_;
+ $DegOfDiff,$STD,$SKEW,$options) = @_;
my $row = '';
$row .= ' | '.
''.
$resource->{'title'}.''.
' | ';
- $row .= ''.$part.' | ' if (defined($part));
+ $row .= ''.$part.' | ' if ($options !~ /no part/);
foreach ($num,$tries) {
$row .= ''.$_.' | ';
}
- foreach ($mod,$mean) {
+ foreach ($mod) {
+ $row .= ''.$_.' | ';
+ }
+ foreach ($mean) {
$row .= ''.
sprintf("%5.2f",$_).' | ';
}
@@ -481,71 +712,126 @@ sub statistics_html_table_data {
return $row;
}
-
###############################################
###############################################
-sub BuildGraphicChart {
- my ($graph,$cacheDB,$courseDescription,$students,$courseID,$r,$c)=@_;
- my %cache;
- my $max;
- my $title = '';
- if($graph eq 'DoDiffGraph') {
- $title = 'Degree-of-Difficulty';
- } else {
- $title = 'Wrong-Percentage';
- }
- my $currentSequence = -1;
- my $sortProblems = 'Sort Within Sequence';
- my ($result, $orderedProblems) =
- &InitializeProblemStatistics($cacheDB, $students, $courseID, $c, $r);
- if($result ne 'OK') {
- return;
+=pod
+
+=item &plot_statistics()
+
+=cut
+
+###############################################
+###############################################
+sub plot_statistics {
+ my ($r,$datafield) = @_;
+ my @Data;
+ #
+ my %Fields = ('#Stdnts'=> 0,
+ 'Tries' => 1,
+ 'Mod' => 2,
+ 'Mean' => 3,
+ '#YES' => 4,
+ '#yes' => 5,
+ '%Wrng' => 9,
+ 'DoDiff' => 6,
+ 'S.D.' => 7,
+ 'Skew' => 8,);
+ #
+ my $field = '%Wrng';
+ foreach (keys(%Fields)) {
+ $field = $_ if ($datafield eq $_);
}
- my @values = ();
- unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
- return 'Unable to tie database.7';
- }
- foreach(@$orderedProblems) {
- my ($sequence,$problem,$part)=split(':', $_);
- if($cache{'StatisticsMaps'} ne 'All Maps' &&
- $cache{'StatisticsMaps'} ne $cache{$sequence.':title'}) {
- next;
- }
- if( $currentSequence == -1 ||
- ($sortProblems eq 'Sort Within Sequence' &&
- $currentSequence != $sequence)) {
- if($currentSequence != -1) {
- &DrawGraph(\@values,$courseDescription,$title,$max,$r);
- }
- if($sortProblems eq 'Sort Within Sequence') {
- $r->print('
'.$cache{$sequence.':title'}.''."\n");
+ my $fieldindex = $Fields{$field};
+ #
+ my $Max = 0;
+ 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'}}) {
+ my @Results = &Apache::loncoursedata::get_problem_statistics
+ (undef,$resource->{'symb'},$part,
+ $ENV{'request.course.id'});
+ my ($num,$Solved,$solved) = @Results[0,4,5];
+ my $wrongpercent = 0;
+ if (defined($num) && $num > 0) {
+ $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10;
+ }
+ push (@Results,$wrongpercent);
+ my $data = $Results[$fieldindex];
+ $data = 0 if ($data eq 'nan');
+ $Max = $data if ($Max<$data);
+ push (@Data,$data);
}
- $currentSequence = $sequence;
- @values = ();
- $max=0;
- }
- my $data = 0;
- if($graph eq 'DoDiffGraph') {
- $data = sprintf("%.2f", $cache{$_.':degreeOfDifficulty'}),
- } else {
- $data = sprintf("%.1f", $cache{$_.':percentWrong'}),
}
- if($max < $data) {
- $max = $data;
+ }
+ #
+ # Print out plot request
+ my $title = 'Percent Wrong';
+ if ($field eq 'DoDiff') {
+ $title = 'Degree of Difficulty';
+ }
+ my $yaxis = 'Percent';
+ if ($field eq 'DoDiff') {
+ $yaxis = '';
+ } elsif ($field ne '%Wrng') {
+ $yaxis = '';
+ }
+ #
+ # Determine appropriate value for $Max
+ if ($field eq 'DoDiff') {
+ if ($Max > 0.5) {
+ $Max = 1;
+ } elsif ($Max > 0.2) {
+ $Max = 0.5;
+ } elsif ($Max > 0.1) {
+ $Max = 0.2;
+ }
+ } elsif ($field eq '%Wrng') {
+ if ($Max > 50) {
+ $Max = 100;
+ } elsif ($Max > 25) {
+ $Max = 50;
+ } elsif ($Max > 20) {
+ $Max = 25;
+ } elsif ($Max > 10) {
+ $Max = 20;
+ } elsif ($Max > 5) {
+ $Max = 10;
+ } else {
+ $Max = 5;
}
- push(@values, $data);
}
- untie(%cache);
- &DrawGraph(\@values,$courseDescription,$title,$max,$r);
+
+ $r->print("".&DrawGraph(\@Data,$title,'Problem Number',$yaxis,
+ $Max)."
\n");
+ #
+ # Print out the data
+ $ENV{'form.sortby'} = 'Contents';
+ &output_html_ungrouped($r,'show probnum');
return;
}
+###############################################
+###############################################
+
+=pod
+
+=item &DrawGraph()
+
+=cut
+
+###############################################
+###############################################
sub DrawGraph {
- my ($values,$courseDescription,$title,$Max,$r)=@_;
+ my ($values,$title,$xaxis,$yaxis,$Max)=@_;
+ $title = '' if (! defined($title));
+ $xaxis = '' if (! defined($xaxis));
+ $yaxis = '' if (! defined($yaxis));
+ #
my $sendValues = join(',', @$values);
my $sendCount = scalar(@$values);
- $r->print("
The Maximum Value is: $Max");
if ( $Max > 1 ) {
if ($Max % 10) {
if ( int($Max) < $Max ) {
@@ -553,196 +839,25 @@ sub DrawGraph {
$Max = int($Max);
}
}
- #(10 - $Max % 10);
- } else { $Max = 1; }
- my @GData = ('','Problem_number',$title,$Max,$sendCount,$sendValues);
-# $r->print(''."\n");
- $r->print('
'."\n");
- $r->print('');
-# $r->print('