--- loncom/interface/statistics/lonproblemstatistics.pm 2004/03/01 16:39:19 1.69 +++ loncom/interface/statistics/lonproblemstatistics.pm 2004/03/23 16:35:15 1.71 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonproblemstatistics.pm,v 1.69 2004/03/01 16:39:19 matthew Exp $ +# $Id: lonproblemstatistics.pm,v 1.71 2004/03/23 16:35:15 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -57,7 +57,8 @@ use Apache::loncoursedata; use Apache::lonstatistics; use Apache::lonlocal; use Spreadsheet::WriteExcel; - +use Apache::lonstathelpers(); +use Time::HiRes; ## ## Localization notes: ## @@ -167,6 +168,15 @@ my @Fields = ( sortable => 'yes', graphable => 'yes', long_title => 'Percent of students whose final answer is wrong' }, + { name => 'deg_of_disc', + title => 'Deg of Disc', + align => 'right', + color => '#FFFFE6', + format => '%4.2f', + sortable => 'yes', + graphable => 'yes', + long_title => 'Degree of Discrimination' }, + ); ############################################### @@ -185,19 +195,19 @@ select sections, maps, and output. ############################################### my @OutputOptions = ( - { name => 'problem statistics grouped by sequence', + { name => 'grouped by sequence', value => 'HTML problem statistics grouped', description => 'Output statistics for the problem parts.', mode => 'html', show => 'grouped', }, - { name => 'problem statistics ungrouped', + { name => 'ungrouped', value => 'HTML problem statistics ungrouped', description => 'Output statistics for the problem parts.', mode => 'html', show => 'ungrouped', }, - { name => 'problem statistics, Excel', + { name => 'Excel', value => 'Excel problem statistics', description => 'Output statistics for the problem parts '. 'in an Excel workbook', @@ -216,6 +226,8 @@ sub CreateInterface { $Str .= ''.&mt('Enrollment Status').''; $Str .= ''.&mt('Sequences and Folders').''; $Str .= ''.&mt('Output').''; + $Str .= ''. + &Apache::lonstathelpers::limit_by_time_form().''; $Str .= ''."\n"; # $Str .= ''."\n"; @@ -280,6 +292,8 @@ sub BuildProblemStatisticsPage { # &Apache::lonstatistics::PrepareClasslist(); # + &Apache::loncoursedata::populate_weight_table(); + # my ($interface,$output_mode,$show) = &CreateInterface(); $r->print($interface); $r->print(''); @@ -297,7 +311,16 @@ sub BuildProblemStatisticsPage { $r->print("

". $ENV{'course.'.$ENV{'request.course.id'}.'.description'}. "

\n"); - $r->print("

".localtime(time)."

"); + my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); + if (defined($starttime) || defined($endtime)) { + # Inform the user what the time limits on the data are. + $r->print('

'.&mt('Statistics on submissions from [_1] to [_2]', + &Apache::lonlocal::locallocaltime($starttime), + &Apache::lonlocal::locallocaltime($endtime)). + '

'); + } + $r->print("

".&mt('Compiled on [_1]', + &Apache::lonlocal::locallocaltime(time))."

"); $r->rflush(); if ($show eq 'grouped') { &output_html_grouped_by_sequence($r); @@ -503,6 +526,8 @@ sub output_excel { $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. time.'_'.rand(1000000000).'.xls'; # + my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); + # my $excel_workbook = undef; my $excel_sheet = undef; # @@ -561,6 +586,22 @@ sub output_excel { $excel_sheet->write($rows_output,$cols_output++,$sectionstring); $cols_output += scalar(@Sections); # + # Time restrictions + my $time_string; + if (defined($starttime)) { + # call localtime but not lonlocal:locallocaltime because excel probably + # cannot handle localized text. Probably. + $time_string .= 'Data collected from '.localtime($time_string); + if (defined($endtime)) { + $time_string .= ' to '.localtime($endtime); + } + $time_string .= '.'; + } elsif (defined($endtime)) { + # See note above about lonlocal:locallocaltime + $time_string .= 'Data collected before '.localtime($endtime).'.'; + } + + # # Put the date in there too $excel_sheet->write($rows_output,$cols_output++, 'Compiled on '.localtime(time)); @@ -782,16 +823,36 @@ sub plot_statistics { return; } +######################################################## +######################################################## + +=pod + +=item &get_statistics() + +Wrapper routine from the call to loncoursedata::get_problem_statistics. +Calls lonstathelpers::get_time_limits() to limit the data set by time. + +Inputs: $sequence, $resource, $part, $problem_num + +Returns: Hash reference with statistics data from +loncoursedata::get_problem_statistics. + +=cut + +######################################################## +######################################################## sub get_statistics { my ($sequence,$resource,$part,$problem_num) = @_; # + my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); my $symb = $resource->{'symb'}; my $courseid = $ENV{'request.course.id'}; # my $data = &Apache::loncoursedata::get_problem_statistics (\@Apache::lonstatistics::SelectedSections, $Apache::lonstatistics::enrollment_status, - $symb,$part,$courseid); + $symb,$part,$courseid,$starttime,$endtime); $data->{'part'} = $part; $data->{'problem_num'} = $problem_num; $data->{'container'} = $sequence->{'title'}; @@ -799,9 +860,66 @@ sub get_statistics { $data->{'title.link'} = $resource->{'src'}.'?symb='. &Apache::lonnet::escape($resource->{'symb'}); # + $data->{'deg_of_disc'} = &compute_discrimination_factor($resource,$part,$sequence); return $data; } + +############################################### +############################################### + +=pod + +=item &compute_discrimination_factor() + +Inputs: $Resource, $Sequence + +Returns: integer between -1 and 1 + +=cut + +############################################### +############################################### +sub compute_discrimination_factor { + my ($resource,$part,$sequence) = @_; + &Apache::lonnet::logthis($sequence->{'title'}.' '.$resource->{'title'}); + my @Resources; + foreach my $res (@{$sequence->{'contents'}}) { + next if ($res->{'symb'} eq $resource->{'symb'}); + push (@Resources,$res->{'symb'}); + } + # + # rank + my $ranking = + &Apache::loncoursedata::rank_students_by_scores_on_resources + (\@Resources, + \@Apache::lonstatistics::SelectedSections, + $Apache::lonstatistics::enrollment_status,undef); + # + # compute their percent scores on the problems in the sequence, + my $number_to_grab = int(scalar(@{$ranking})/4); + my $num_students = scalar(@{$ranking}); + my @BottomSet = map { $_->[&Apache::loncoursedata::RNK_student()]; + } @{$ranking}[0..$number_to_grab]; + my @TopSet = + map { + $_->[&Apache::loncoursedata::RNK_student()]; + } @{$ranking}[($num_students-$number_to_grab)..($num_students-1)]; + my ($bottom_sum,$bottom_max) = + &Apache::loncoursedata::get_sum_of_scores($resource,$part,\@BottomSet); + my ($top_sum,$top_max) = + &Apache::loncoursedata::get_sum_of_scores($resource,$part,\@TopSet); + my $deg_of_disc; + if ($top_max == 0 || $bottom_max==0) { + $deg_of_disc = 'nan'; + } else { + $deg_of_disc = ($top_sum/$top_max) - ($bottom_sum/$bottom_max); + } + #&Apache::lonnet::logthis(' '.$top_sum.'/'.$top_max. + # ' - '.$bottom_sum.'/'.$bottom_max); + return $deg_of_disc; +} + ############################################### ###############################################