--- loncom/interface/statistics/lonproblemstatistics.pm 2005/08/26 21:53:23 1.105 +++ loncom/interface/statistics/lonproblemstatistics.pm 2011/01/17 00:19:41 1.119 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonproblemstatistics.pm,v 1.105 2005/08/26 21:53:23 albertel Exp $ +# $Id: lonproblemstatistics.pm,v 1.119 2011/01/17 00:19:41 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,6 +52,7 @@ package Apache::lonproblemstatistics; use strict; use Apache::lonnet; use Apache::loncommon(); +use Apache::lonquickgrades(); use Apache::lonhtmlcommon; use Apache::loncoursedata; use Apache::lonstatistics; @@ -60,6 +61,8 @@ use Apache::lonlocal; use Spreadsheet::WriteExcel; use Apache::lonstathelpers(); use Time::HiRes; +use LONCAPA; + my @StatsArray; my %SeqStat; # keys are symbs, values are hash refs @@ -121,11 +124,11 @@ my @Fields = ( align => 'left', color => '#FFFFE6', special => 'link', - sortable => 'yes', + sortable => 'yes', selectable => 'no', defaultselected => 'yes', }, - { name => 'part', + { name => 'part', title => 'Part', align => 'left', color => '#FFFFE6', @@ -373,7 +376,7 @@ my @SeqFields = ( align => 'left', color => '#FFFFE6', special => 'no', - sortable => 'no', + sortable => 'no', selectable => 'yes', defaultselected => 'no', }, @@ -508,7 +511,7 @@ my @SeqFields = ( long_title => 'KR-21 reliability statistic', selectable => 'yes', defaultselected => 'no', - }, + }, ); my %SelectedFields; @@ -575,7 +578,7 @@ sub parse_field_selection { } sub field_selection_input { - my $Str = ''."\n"; $Str .= ''."\n"; foreach my $field (@Fields) { next if ($field->{'selectable'} ne 'yes'); @@ -608,39 +611,49 @@ sub CreateInterface { &parse_field_selection(); # my $Str = ''; - $Str .= &Apache::lonhtmlcommon::breadcrumbs - (undef,'Overall Problem Statistics','Statistics_Overall_Key'); - $Str .= ''."\n"; - $Str .= ''; - $Str .= ''; - $Str .= ''; - $Str .= ''; - $Str .= ''; - $Str .= ''; - $Str .= ''."\n"; + $Str .= '

'; + $Str .= &Apache::loncommon::start_data_table(); + $Str .= &Apache::loncommon::start_data_table_header_row(); + $Str .= '

'; + $Str .= ''; + $Str .= ''; + $Str .= ''; + $Str .= ''; + $Str .= ''; + $Str .= ''; + $Str .= &Apache::loncommon::end_data_table_header_row(); # - $Str .= ''."\n"; - $Str .= '
'.&mt('Sections').''.&mt('Enrollment Status').''.&mt('Sequences and Folders').''.&mt('Statistics').''. - &Apache::lonstathelpers::limit_by_time_form().'
'.&mt('Sections').''.&mt('Groups').''.&mt('Access Status').''.&mt('Sequences and Folders').''.&mt('Statistics').''.&mt('Plot Graph').''.&mt('Time Period').'
'."\n"; + $Str .= &Apache::loncommon::start_data_table_row(); + $Str .= ''."\n"; $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5); - $Str .= ''; + $Str .= ''; + $Str .= &Apache::lonstatistics::GroupSelect('Group','multiple',5); + $Str .= ''; $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5); - $Str .= ''; + $Str .= ''; # $Str .= &Apache::lonstatistics::map_select('Maps','multiple,all',5); - $Str .= ''.&field_selection_input(); - $Str .= '
'."\n"; - # - $Str .= '

'.&mt('Status: [_1]', - '' - ). - '

'; + $Str .= ''; + $Str .= &field_selection_input(); + $Str .= ''; + $Str .= &plot_dropdown(); + $Str .= ''."\n"; + $Str .= ''; + $Str .= &Apache::lonstathelpers::limit_by_time_form(); + $Str .= ''."\n"; + $Str .= &Apache::loncommon::end_data_table_row(); + $Str .= &Apache::loncommon::end_data_table(); + # + $Str .= '

' + .&mt('Status: [_1]', + '') + .'

'; # + $Str .= '

'; $Str .= ''; - $Str .= ' 'x5; - $Str .= 'Plot '.&plot_dropdown().(' 'x10); + $Str .= (' 'x10); # return $Str; } @@ -674,6 +687,7 @@ sub BuildProblemStatisticsPage { my %Saveable_Parameters = ('Status' => 'scalar', 'statsoutputmode' => 'scalar', 'Section' => 'array', + 'Groups' => 'array', 'StudentData' => 'array', 'Maps' => 'array', 'fieldselections'=> 'array'); @@ -689,12 +703,16 @@ sub BuildProblemStatisticsPage { undef(%SeqStat); # # Finally let the user know we are here + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Overall Problem Statistics', + 'Statistics_Overall_Key')); + &Apache::lonquickgrades::startGradeScreen($r,'statistics'); + my $interface = &CreateInterface($r); $r->print($interface); $r->print(''); # - my @CacheButtonHTML = + my @CacheButtonHTML = &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status'); my $Str; foreach my $html (@CacheButtonHTML) { @@ -703,12 +721,13 @@ sub BuildProblemStatisticsPage { # $r->print($Str); if (! exists($env{'form.firstrun'})) { - $r->print('

'. + $r->print('

'. &mt('Press "Generate Statistics" when you are ready.'). - '

'. + '

'. + '

'. &mt('It may take some time to update the student data '. - 'for the first analysis. Future analysis this session '. - ' will not have this delay.'). + 'for the first analysis. Future analysis this session '. + 'will not have this delay.'). '

'); &clean_up(); return; @@ -719,10 +738,10 @@ sub BuildProblemStatisticsPage { # it does not slow things down noticably. &Apache::loncoursedata::populate_weight_table(); # - ($navmap,@sequences) = + ($navmap,@sequences) = &Apache::lonstatistics::selected_sequences_with_assessments(); if (! ref($navmap)) { - $r->print('

'.&mt('A course-wide error occured.').'

'. + $r->print('
'.&mt('A course-wide error occurred.').'
'. '

'.$navmap.'

'); &clean_up(); return; @@ -732,7 +751,7 @@ sub BuildProblemStatisticsPage { &Apache::lonstatistics::section_and_enrollment_description(). ''); &Excel_output($r); - } else { + } else { $r->print(''.' 'x5); $r->rflush(); @@ -741,7 +760,7 @@ sub BuildProblemStatisticsPage { ''); my $count = 0; foreach my $seq (@sequences) { - my @resources = + my @resources = &Apache::lonstathelpers::get_resources($navmap,$seq); $count += scalar(@resources); } @@ -786,7 +805,7 @@ sub output_sequence_statistics { ''."\n". ''); $r->print(&sequence_html_header()); - foreach my $seq (@sequences) { + foreach my $seq (@sequences) { last if ($c->aborted); &compute_sequence_statistics($seq); $r->print(&sequence_html_output($seq)); @@ -1009,7 +1028,7 @@ sub make_single_stat_plot { } # # Build up the data sets to plot - my @Labels; + my @Labels; my @Data; my $max = 1; foreach my $data (@StatsArray) { @@ -1049,7 +1068,7 @@ sub degrees_plot { my $plot = ''; my $ymax = 0; my $ymin = 0; - my @Disc; my @Diff; my @Labels; + my @Disc; my @Diff; my @Labels; foreach my $data (@StatsArray) { push(@Labels,$data->{'problem_num'}); my $disc = $data->{'deg_of_disc'}; @@ -1139,7 +1158,7 @@ sub degrees_plot { END - my $plotresult = + my $plotresult = '

'.&Apache::lonxml::xmlparse($r,'web',$plot).'

'.$/; $r->print($plotresult); return; @@ -1224,7 +1243,7 @@ sub tries_data_plot { END - my $plotresult = + my $plotresult = '

'.&Apache::lonxml::xmlparse($r,'web',$plot).'

'.$/; $r->print($plotresult); return; @@ -1310,6 +1329,7 @@ sub Excel_output { &Apache::lonstatistics::section_and_enrollment_description('plaintext'), $format->{'h3'}); $cols_output += scalar(&Apache::lonstatistics::get_selected_sections()); + $cols_output += scalar(&Apache::lonstatistics::get_selected_groups()); # # Time restrictions my $time_string; @@ -1334,11 +1354,11 @@ sub Excel_output { $excel_sheet->write($rows_output,$cols_output++, 'Compiled on '.localtime(time)); # - $rows_output++; + $rows_output++; $cols_output=0; ## ## Sequence Statistics - ## + ## &write_headers($excel_sheet,$format,\$rows_output,\$cols_output, \@SeqFields); foreach my $seq (@sequences) { @@ -1416,7 +1436,7 @@ sub write_headers { foreach my $field (@{$Fields}) { next if ($field->{'selected'} ne 'yes'); next if ($field->{'name'} eq 'problem_num'); - # Use english for excel as I am not sure how well excel handles + # Use english for excel as I am not sure how well excel handles # other character sets.... $excel_sheet->write($$rows_output,$$cols_output, $field->{'title'}, @@ -1440,7 +1460,7 @@ sub compute_statistics_on_sequence { my @Data; foreach my $res (&Apache::lonstathelpers::get_resources($navmap,$seq)) { foreach my $part (@{$res->parts}) { - next if ($res->is_survey($part)); + next if (($res->is_survey($part)) || ($res->is_anonsurvey($part))) ; # # This is where all the work happens my $data = &get_statistics($seq,$res,$part,scalar(@StatsArray)+1); @@ -1529,13 +1549,13 @@ sub sort_data { =item &get_statistics() -Wrapper routine from the call to loncoursedata::get_problem_statistics. +Wrapper routine from the call to loncoursedata::get_problem_statistics. Calls lonstathelpers::get_time_limits() to limit the data set by time and &compute_discrimination_factor Inputs: $sequence, $resource, $part, $problem_num -Returns: Hash reference with statistics data from +Returns: Hash reference with statistics data from loncoursedata::get_problem_statistics. =cut @@ -1551,6 +1571,7 @@ sub get_statistics { # my $data = &Apache::loncoursedata::get_problem_statistics ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, $symb,$part,$courseid,$starttime,$endtime); $data->{'symb'} = $symb; @@ -1559,10 +1580,10 @@ sub get_statistics { $data->{'container'} = $sequence->compTitle; $data->{'title'} = $resource->compTitle; $data->{'title.link'} = $resource->src.'?symb='. - &Apache::lonnet::escape($resource->symb); + &escape($resource->symb); # if ($SelectedFields{'deg_of_disc'}) { - $data->{'deg_of_disc'} = + $data->{'deg_of_disc'} = &compute_discrimination_factor($resource,$part,$sequence); } # @@ -1575,9 +1596,9 @@ sub get_statistics { $data->{'course'} = $env{'request.course.id'}; my $urlres=(&Apache::lonnet::decode_symb($resource->symb))[2]; $data->{'urlres'}=$urlres; - my %storestats = + my %storestats = &LONCAPA::lonmetadata::dynamic_metadata_storage($data); - my ($dom,$user) = $urlres=~/^(\w+)\/(\w+)/; + my ($dom,$user) = ($urlres=~m{^($LONCAPA::domain_re)/($LONCAPA::username_re)}); &Apache::lonnet::put('nohist_resevaldata',\%storestats,$dom,$user); } # @@ -1585,16 +1606,16 @@ sub get_statistics { ($data->{'num_solved'}+0.1); # # Get the due date for research purposes (commented out most of the time) -# $data->{'duedate'} = -# &Apache::lonnet::EXT('resource.'.$part.'.duedate',$symb); -# $data->{'opendate'} = -# &Apache::lonnet::EXT('resource.'.$part.'.opendate',$symb); -# $data->{'maxtries'} = -# &Apache::lonnet::EXT('resource.'.$part.'.maxtries',$symb); -# $data->{'hinttries'} = -# &Apache::lonnet::EXT('resource.'.$part.'.hinttries',$symb); - $data->{'weight'} = - &Apache::lonnet::EXT('resource.'.$part.'.weight',$symb); +# my $duedate = &Apache::lonnet::EXT('resource.'.$part.'.duedate',$symb);; +# my $opendate = &Apache::lonnet::EXT('resource.'.$part.'.opendate',$symb); +# my $maxtries = &Apache::lonnet::EXT('resource.'.$part.'.maxtries',$symb); +# my $hinttries = &Apache::lonnet::EXT('resource.'.$part.'.hinttries',$symb); + my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',$symb); + $data->{'weight'} = $weight; +# $data->{'duedate'} = $duedate; +# $data->{'opendate'} = $opendate; +# $data->{'maxtries'} = $maxtries; +# $data->{'hinttries'} = $hinttries; # $data->{'resptypes'} = join(',',@{$resource->{'partdata'}->{$part}->{'ResponseTypes'}}); return $data; } @@ -1625,30 +1646,31 @@ sub compute_discrimination_factor { # # rank my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); - my $ranking = + my $ranking = &Apache::loncoursedata::rank_students_by_scores_on_resources (\@Resources, [&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status,undef, - $starttime,$endtime); + $starttime,$endtime, $symb); # # 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()]; + 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 @TopSet = + map { + $_->[&Apache::loncoursedata::RNK_student()]; + } @{$ranking}[-$number_to_grab..0]; if (! @BottomSet || (@BottomSet == 1 && $BottomSet[0] eq '') || ! @TopSet || (@TopSet == 1 && $TopSet[0] eq '')) { return 'nan'; } - my ($bottom_sum,$bottom_max) = + my ($bottom_sum,$bottom_max) = &Apache::loncoursedata::get_sum_of_scores($symb,$part,\@BottomSet, undef,$starttime,$endtime); - my ($top_sum,$top_max) = + my ($top_sum,$top_max) = &Apache::loncoursedata::get_sum_of_scores($symb,$part,\@TopSet, undef,$starttime,$endtime); my $deg_of_disc; @@ -1671,10 +1693,10 @@ sub compute_discrimination_factor { ## ## K=the number of items in your test ## M=the mean score on the test -## s=the standard deviation of the scores on your test +## s=the standard deviation of the scores on your test ## ## then: -## +## ## KR-21 rk= [K/(K-1)] * [1- (M*(K-M))/(K*s^2))] ## ############################################### @@ -1691,9 +1713,10 @@ sub compute_sequence_statistics { my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); # # First compute statistics based on student scores - my ($smin,$smax,$sMean,$sSTD,$scount,$sMAX) = + my ($smin,$smax,$sMean,$sSTD,$scount,$sMAX) = &Apache::loncoursedata::score_stats ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, \@Resources,$starttime,$endtime,undef); $SeqStat{$symb}->{'title'} = $seq->compTitle; @@ -1705,10 +1728,11 @@ sub compute_sequence_statistics { $SeqStat{$symb}->{'max_possible'} = $sMAX; # # Compute statistics based on the number of correct problems - # 'correct' is taken to mean + # 'correct' is taken to mean my ($cmin,$cmax,$cMean,$cSTD,$ccount)= &Apache::loncoursedata::count_stats ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, \@Resources,$starttime,$endtime,undef); my $K = $part_count;