--- loncom/interface/statistics/lonproblemstatistics.pm 2005/03/03 18:56:26 1.98 +++ loncom/interface/statistics/lonproblemstatistics.pm 2008/10/23 09:07:51 1.114 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonproblemstatistics.pm,v 1.98 2005/03/03 18:56:26 matthew Exp $ +# $Id: lonproblemstatistics.pm,v 1.114 2008/10/23 09:07:51 bisitz Exp $ # # Copyright Michigan State University Board of Trustees # @@ -50,7 +50,7 @@ Excel files, and plots. package Apache::lonproblemstatistics; use strict; -use Apache::lonnet(); +use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon; use Apache::loncoursedata; @@ -60,6 +60,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 @@ -362,7 +364,7 @@ my @Fields = ( sortable => 'no', graphable => 'no', long_title => 'Problem weight (for instructor)', - selectable => 'no', + selectable => 'yes', defaultselected => 'yes', }, ); @@ -516,35 +518,35 @@ my %SelectedFields; sub parse_field_selection { # # Pull out the defaults - if (! defined($ENV{'form.fieldselections'})) { - $ENV{'form.fieldselections'} = []; + if (! defined($env{'form.fieldselections'})) { + $env{'form.fieldselections'} = []; foreach my $field (@Fields) { next if ($field->{'selectable'} ne 'yes'); if ($field->{'defaultselected'} eq 'yes') { - push(@{$ENV{'form.fieldselections'}},$field->{'name'}); + push(@{$env{'form.fieldselections'}},$field->{'name'}); } } } # # Make sure the data we are plotting is there my %NeededFields; - if (exists($ENV{'form.plot'}) && $ENV{'form.plot'} ne '' && - $ENV{'form.plot'} ne 'none') { - if ($ENV{'form.plot'} eq 'degrees') { + if (exists($env{'form.plot'}) && $env{'form.plot'} ne '' && + $env{'form.plot'} ne 'none') { + if ($env{'form.plot'} eq 'degrees') { $NeededFields{'deg_of_diff'}++; $NeededFields{'deg_of_disc'}++; - } elsif ($ENV{'form.plot'} eq 'tries statistics') { + } elsif ($env{'form.plot'} eq 'tries statistics') { $NeededFields{'mean_tries'}++; $NeededFields{'std_tries'}++; $NeededFields{'problem_num'}++; } else { - $NeededFields{$ENV{'form.plot'}}++; + $NeededFields{$env{'form.plot'}}++; } } # # This should not happen, but in case it does... - if (ref($ENV{'form.fieldselections'}) ne 'ARRAY') { - $ENV{'form.fieldselections'} = [$ENV{'form.fieldselections'}]; + if (ref($env{'form.fieldselections'}) ne 'ARRAY') { + $env{'form.fieldselections'} = [$env{'form.fieldselections'}]; } # # Set the field data and the selected fields (for easier checking) @@ -559,7 +561,7 @@ sub parse_field_selection { $field->{'selected'} = 'yes'; $SelectedFields{$field->{'name'}}++; } - foreach my $selection (@{$ENV{'form.fieldselections'}}) { + foreach my $selection (@{$env{'form.fieldselections'}}) { if ($selection eq $field->{'name'} || $selection eq 'all') { $field->{'selected'} = 'yes'; $SelectedFields{$field->{'name'}}++; @@ -608,12 +610,13 @@ sub CreateInterface { &parse_field_selection(); # my $Str = ''; - $Str .= &Apache::lonhtmlcommon::breadcrumbs - (undef,'Overall Problem Statistics','Statistics_Overall_Key'); + $Str .= &Apache::lonhtmlcommon::breadcrumbs('Overall Problem Statistics', + 'Statistics_Overall_Key'); $Str .= ''."\n"; $Str .= ''; $Str .= ''; - $Str .= ''; + $Str .= ''; + $Str .= ''; $Str .= ''; $Str .= ''; $Str .= ''."\n"; $Str .= '
'.&mt('Sections').''.&mt('Enrollment Status').''.&mt('Groups').''.&mt('Access Status').''.&mt('Sequences and Folders').''.&mt('Statistics').''. @@ -623,6 +626,8 @@ sub CreateInterface { $Str .= '
'."\n"; $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5); $Str .= ''; + $Str .= &Apache::lonstatistics::GroupSelect('Group','multiple',5); + $Str .= ''; $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5); $Str .= ''; # @@ -631,11 +636,11 @@ sub CreateInterface { $Str .= '
'."\n"; # - $Str .= '

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

'; + $Str .= '

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

'; # $Str .= ''; @@ -661,6 +666,11 @@ Main interface to problem statistics. my $navmap; my @sequences; +sub clean_up { + undef($navmap); + undef(@sequences); +} + sub BuildProblemStatisticsPage { my ($r,$c)=@_; undef($navmap); @@ -669,6 +679,7 @@ sub BuildProblemStatisticsPage { my %Saveable_Parameters = ('Status' => 'scalar', 'statsoutputmode' => 'scalar', 'Section' => 'array', + 'Groups' => 'array', 'StudentData' => 'array', 'Maps' => 'array', 'fieldselections'=> 'array'); @@ -686,7 +697,7 @@ sub BuildProblemStatisticsPage { # Finally let the user know we are here my $interface = &CreateInterface($r); $r->print($interface); - $r->print(''); # my @CacheButtonHTML = @@ -697,14 +708,15 @@ sub BuildProblemStatisticsPage { } # $r->print($Str); - if (! exists($ENV{'form.firstrun'})) { + if (! exists($env{'form.firstrun'})) { $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.'). + 'will not have this delay.'). '

'); + &clean_up(); return; } $r->rflush(); @@ -713,20 +725,27 @@ sub BuildProblemStatisticsPage { # it does not slow things down noticably. &Apache::loncoursedata::populate_weight_table(); # - if (exists($ENV{'form.Excel'})) { + ($navmap,@sequences) = + &Apache::lonstatistics::selected_sequences_with_assessments(); + if (! ref($navmap)) { + $r->print('

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

'. + '

'.$navmap.'

'); + &clean_up(); + return; + } + if (exists($env{'form.Excel'})) { + $r->print('

'. + &Apache::lonstatistics::section_and_enrollment_description(). + '

'); &Excel_output($r); } else { $r->print(''.' 'x5); $r->rflush(); + $r->print('

'. + &Apache::lonstatistics::section_and_enrollment_description(). + '

'); my $count = 0; - ($navmap,@sequences) = - &Apache::lonstatistics::selected_sequences_with_assessments(); - if (! ref($navmap)) { - $r->print('

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

'. - '

'.$navmap.'

'); - return; - } foreach my $seq (@sequences) { my @resources = &Apache::lonstathelpers::get_resources($navmap,$seq); @@ -742,9 +761,9 @@ sub BuildProblemStatisticsPage { $r->rflush(); } # - my $sortby = $ENV{'form.sortby'}; + my $sortby = $env{'form.sortby'}; $sortby = 'container' if (! defined($sortby) || $sortby =~ /^\s*$/); - my $plot = $ENV{'form.plot'}; + my $plot = $env{'form.plot'}; if ($plot eq '' || $plot eq 'none') { undef($plot); } @@ -759,6 +778,7 @@ sub BuildProblemStatisticsPage { &output_sequence_statistics($r); } } + &clean_up(); return; } @@ -819,7 +839,7 @@ sub output_html_stats { my ($r)=@_; &compute_all_statistics($r); $r->print(&html_preamble()); - &sort_data($ENV{'form.sortby'}); + &sort_data($env{'form.sortby'}); # my $count=0; foreach my $data (@StatsArray) { @@ -841,7 +861,7 @@ sub output_html_stats { sub html_preamble { my $Str=''; $Str .= "

". - $ENV{'course.'.$ENV{'request.course.id'}.'.description'}. + $env{'course.'.$env{'request.course.id'}.'.description'}. "

\n"; my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); if (defined($starttime) || defined($endtime)) { @@ -965,7 +985,7 @@ sub sequence_html_output { sub make_plot { my ($r,$plot) = @_; &compute_all_statistics($r); - &sort_data($ENV{'form.sortby'}); + &sort_data($env{'form.sortby'}); if ($plot eq 'degrees') { °rees_plot($r); } elsif ($plot eq 'tries statistics') { @@ -1219,8 +1239,8 @@ END sub plot_dropdown { my $current = ''; # - if (defined($ENV{'form.plot'})) { - $current = $ENV{'form.plot'}; + if (defined($env{'form.plot'})) { + $current = $env{'form.plot'}; } # my @Additional_Plots = ( @@ -1264,40 +1284,21 @@ sub Excel_output { &compute_all_statistics($r); my $c = $r->connection; return if ($c->aborted()); + # + my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); ## ## Create the excel workbook - my $filename = '/prtspool/'. - $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. - time.'_'.rand(1000000000).'.xls'; - my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); - # - # Create sheet - my $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(&mt("Problems creating new Excel file. ". - "This error has been logged. ". - "Please alert your LON-CAPA administrator.")); - return 0; - } - # - # 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); + my ($excel_workbook,$filename,$format) = + &Apache::loncommon::create_workbook($r); + return if (! defined($excel_workbook)); # # Add a worksheet - my $sheetname = $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; + my $sheetname = $env{'course.'.$env{'request.course.id'}.'.description'}; if (length($sheetname) > 31) { $sheetname = substr($sheetname,0,31); } my $excel_sheet = $excel_workbook->addworksheet( &Apache::loncommon::clean_excel_name($sheetname)); - # - my $format = &Apache::loncommon::define_excel_formats($excel_workbook); ## ## Begin creating excel sheet ## @@ -1305,17 +1306,17 @@ sub Excel_output { # # Put the course description in the header $excel_sheet->write($rows_output,$cols_output++, - $ENV{'course.'.$ENV{'request.course.id'}.'.description'}, + $env{'course.'.$env{'request.course.id'}.'.description'}, $format->{'h1'}); $cols_output += 3; # # Put a description of the sections listed my $sectionstring = ''; $excel_sheet->write($rows_output,$cols_output++, - &Apache::lonstathelpers::sections_description - (@Apache::lonstatistics::SelectedSections), + &Apache::lonstatistics::section_and_enrollment_description('plaintext'), $format->{'h3'}); - $cols_output += scalar(@Apache::lonstatistics::SelectedSections); + $cols_output += scalar(&Apache::lonstatistics::get_selected_sections()); + $cols_output += scalar(&Apache::lonstatistics::get_selected_groups()); # # Time restrictions my $time_string; @@ -1553,10 +1554,11 @@ sub get_statistics { # my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits(); my $symb = $resource->symb; - my $courseid = $ENV{'request.course.id'}; + my $courseid = $env{'request.course.id'}; # my $data = &Apache::loncoursedata::get_problem_statistics - (\@Apache::lonstatistics::SelectedSections, + ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, $symb,$part,$courseid,$starttime,$endtime); $data->{'symb'} = $symb; @@ -1565,7 +1567,7 @@ 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'} = @@ -1574,16 +1576,16 @@ sub get_statistics { # # Store in metadata if computations were done for all students if ($data->{'num_students'} > 1) { - my @Sections = @Apache::lonstatistics::SelectedSections; + my @Sections = &Apache::lonstatistics::get_selected_sections(); my $sections = '"'.join(' ',@Sections).'"'; $sections =~ s/&+/_/g; # Ensure no special characters $data->{'sections'}=$sections; - $data->{'course'} = $ENV{'request.course.id'}; + $data->{'course'} = $env{'request.course.id'}; my $urlres=(&Apache::lonnet::decode_symb($resource->symb))[2]; $data->{'urlres'}=$urlres; 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); } # @@ -1591,16 +1593,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; } @@ -1634,9 +1636,10 @@ sub compute_discrimination_factor { my $ranking = &Apache::loncoursedata::rank_students_by_scores_on_resources (\@Resources, - \@Apache::lonstatistics::SelectedSections, + [&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); @@ -1646,7 +1649,7 @@ sub compute_discrimination_factor { my @TopSet = map { $_->[&Apache::loncoursedata::RNK_student()]; - } @{$ranking}[($num_students-$number_to_grab)..($num_students-1)]; + } @{$ranking}[-$number_to_grab..0]; if (! @BottomSet || (@BottomSet == 1 && $BottomSet[0] eq '') || ! @TopSet || (@TopSet == 1 && $TopSet[0] eq '')) { return 'nan'; @@ -1699,7 +1702,8 @@ sub compute_sequence_statistics { # First compute statistics based on student scores my ($smin,$smax,$sMean,$sSTD,$scount,$sMAX) = &Apache::loncoursedata::score_stats - (\@Apache::lonstatistics::SelectedSections, + ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, \@Resources,$starttime,$endtime,undef); $SeqStat{$symb}->{'title'} = $seq->compTitle; @@ -1714,7 +1718,8 @@ sub compute_sequence_statistics { # 'correct' is taken to mean my ($cmin,$cmax,$cMean,$cSTD,$ccount)= &Apache::loncoursedata::count_stats - (\@Apache::lonstatistics::SelectedSections, + ([&Apache::lonstatistics::get_selected_sections()], + [&Apache::lonstatistics::get_selected_groups()], $Apache::lonstatistics::enrollment_status, \@Resources,$starttime,$endtime,undef); my $K = $part_count;