--- loncom/interface/statistics/lonproblemanalysis.pm 2003/10/16 15:24:49 1.41 +++ loncom/interface/statistics/lonproblemanalysis.pm 2004/10/29 15:27:39 1.97 @@ -1,7 +1,6 @@ # The LearningOnline Network with CAPA # - -# $Id: lonproblemanalysis.pm,v 1.41 2003/10/16 15:24:49 matthew Exp $ +# $Id: lonproblemanalysis.pm,v 1.97 2004/10/29 15:27:39 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,7 +24,6 @@ # # http://www.lon-capa.org/ # - package Apache::lonproblemanalysis; use strict; @@ -35,101 +33,139 @@ use Apache::lonhtmlcommon(); use Apache::loncoursedata(); use Apache::lonstatistics; use Apache::lonlocal; +use Apache::lonstathelpers(); +use Apache::lonstudentsubmissions(); use HTML::Entities(); +use Time::Local(); +use Spreadsheet::WriteExcel(); my $plotcolors = ['#33ff00', '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933', '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66', ]; +my @SubmitButtons = ({ name => 'PrevProblemAnalysis', + text => 'Previous Problem' }, + { name => 'ProblemAnalysis', + text => 'Analyze Problem Again' }, + { name => 'NextProblemAnalysis', + text => 'Next Problem' }, + { name => 'break'}, + { name => 'SelectAnother', + text => 'Choose a different Problem' }, + { name => 'ExcelOutput', + text => 'Produce Excel Output' }); + sub BuildProblemAnalysisPage { my ($r,$c)=@_; - $r->print('
'.
- ' |
'. + ''.$title.' (N='.$N.')'. + ''. + ' | ||
'.$min.' | '. + ''.$plotresult.' | '. + ''.$max.' | '. + '
'. + 'Maximum Number of Coinciding Values: '.$max_y. + ' |
'. + ''. + &mt($pre_graph_text, + $plot_num,$foil_choice_data->{'_count'}, + $correct, + $foil_choice_data->{'_count'}-$correct, + @extra_data). + ' | ||||
'.$concept_plot.' | '. + ''.$choice_plot.' | '; + if ($stacked_plot ne '') { + $analysis_html .= + ''.$stacked_plot.' | '. + ''.&build_foil_key($foils,$count_by_foil).' | '; + } else { + $analysis_html .= (''x2); + } + $analysis_html.=' |
'. + $post_graph_text.' | ||||
'.
+ &mt($no_data_text,
+ $plot_num,$foil_choice_data->{'_count'},
+ $correct,
+ $foil_choice_data->{'_count'}-$correct,
+ @extra_data);
+ if (defined($post_graph_text)) {
+ $analysis_html.=' '.$post_graph_text; + } + $analysis_html.=' |
'. + &mt('None of the selected students attempted the problem more than [_1] times.',$try-1). + ' | ||||
'. + &mt('None of the selected students have attempted the problem').' | ||||
'. + ''. + &mt('Attempt [_1], [_2] submissions, [_3] correct, [_4] incorrect', + $try,$data_count,$correct,$data_count-$correct). + ''.' | ||||
'.$concept_graph.' | '. + ''.$correct_graph.' | '. + ''.$incorrect_graph.' | '. + ''.$optionkey.' | '. + ' |
'. + &mt('Data from [_1] to [_2]', + &Apache::lonlocal::locallocaltime($starttime), + &Apache::lonlocal::locallocaltime($endtime)). + ' | |||
'. + &mt('[_1] submissions from [_2] students submitting, [_3] correct, [_4] incorrect', + $data_count,$student_count,$correct,$data_count-$correct). + ' | |||
'.$concept_correct_plot.' | '. + ''.$foil_correct_plot.' | '. + ''.$foil_incorrect_plot.' | '. + ''.$foilkey.' |
'.
+ &mt('Start time: [_1]',$startdateform).' '. + &mt('End time: [_1]',$enddateform).' | |||
  |
'.&mt("Unable to create new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"). + '
'); + return undef; + } + # + $workbook->set_tempdir('/home/httpd/perl/tmp'); + my $format = &Apache::loncommon::define_excel_formats($workbook); + # + # Create and populate main worksheets + my $problem_data_sheet = $workbook->addworksheet('Problem Data'); + my $student_data_sheet = &build_student_data_worksheet($workbook,$format); + my $response_data_sheet = $workbook->addworksheet('Response Data'); + foreach my $sheet ($problem_data_sheet,$student_data_sheet, + $response_data_sheet) { + $sheet->write(0,0,$resource->{'title'},$format->{'h2'}); + $sheet->write(1,0,$resource->{'src'},$format->{'h3'}); + } + # + my $result; + $result = &OR_build_problem_data_worksheet($problem_data_sheet,$format, + $Concepts,$ORdata); + if ($result ne 'okay') { + # Do something useful + } + $result = &OR_build_response_data_worksheet($response_data_sheet,$format, + $performance_data,$Foils, + $ORdata); + if ($result ne 'okay') { + # Do something useful + } + $response_data_sheet->activate(); + # + # Close the excel file + $workbook->close(); + # + # Write a link to allow them to download it + $result .= ''. + &mt('Your Excel spreadsheet.'). + '
'."\n"; + return $result; +} + +sub OR_build_problem_data_worksheet { + my ($worksheet,$format,$Concepts,$ORdata) = @_; + my $rows_output = 3; + my $cols_output = 0; + $worksheet->write($rows_output++,0,'Problem Structure',$format->{'h3'}); + ## + ## + my @Headers; + if (@$Concepts > 1) { + @Headers = ("Concept\nNumber",'Concept',"Foil\nNumber", + 'Foil Name','Foil Text','Correct value'); + } else { + @Headers = ('Foil Number','FoilName','Foil Text','Correct value'); + } + $worksheet->write_row($rows_output++,0,\@Headers,$format->{'header'}); + my %Foildata = %{$ORdata->{'_Foils'}}; + my $conceptindex = 1; + my $foilindex = 1; + foreach my $concept (@$Concepts) { + my @FoilsInConcept = @{$concept->{'foils'}}; + my $firstfoil = shift(@FoilsInConcept); + if (@$Concepts > 1) { + $worksheet->write_row($rows_output++,0, + [$conceptindex, + $concept->{'name'}, + $foilindex++, + $Foildata{$firstfoil}->{'name'}, + $Foildata{$firstfoil}->{'text'}, + $Foildata{$firstfoil}->{'value'},]); + } else { + $worksheet->write_row($rows_output++,0, + [ $foilindex++, + $Foildata{$firstfoil}->{'name'}, + $Foildata{$firstfoil}->{'text'}, + $Foildata{$firstfoil}->{'value'},]); + } + foreach my $foilid (@FoilsInConcept) { + if (@$Concepts > 1) { + $worksheet->write_row($rows_output++,0, + ['', + '', + $foilindex, + $Foildata{$foilid}->{'name'}, + $Foildata{$foilid}->{'text'}, + $Foildata{$foilid}->{'value'},]); + } else { + $worksheet->write_row($rows_output++,0, + [$foilindex, + $Foildata{$foilid}->{'name'}, + $Foildata{$foilid}->{'text'}, + $Foildata{$foilid}->{'value'},]); + } + } continue { + $foilindex++; + } + } continue { + $conceptindex++; + } + $rows_output++; + $rows_output++; + ## + ## Option data output + $worksheet->write($rows_output++,0,'Options',$format->{'header'}); + foreach my $string (@{$ORdata->{'_Options'}}) { + $worksheet->write($rows_output++,0,$string); + } + return 'okay'; +} + +sub OR_build_response_data_worksheet { + my ($worksheet,$format,$performance_data,$Foils,$ORdata)=@_; + my $rows_output = 3; + my $cols_output = 0; + $worksheet->write($rows_output++,0,'Response Data',$format->{'h3'}); + $worksheet->set_column(1,1,20); + $worksheet->set_column(2,2,13); + my @Headers = ('identifier','time','award detail','attempt'); + foreach my $foil (@$Foils) { + push (@Headers,$foil.' submission'); + push (@Headers,$foil.' grading'); + } + $worksheet->write_row($rows_output++,0,\@Headers,$format->{'header'}); + # + foreach my $row (@$performance_data) { + next if (! defined($row)); + my ($student,$award,$grading,$submission,$time,$tries) = @$row; + my @Foilgrades = split('&',$grading); + my @Foilsubs = split('&',$submission); + my %response_data; + for (my $j=0;$j<=$#Foilgrades;$j++) { + my ($foilid,$correct) = split('=',$Foilgrades[$j]); + my (undef,$submission) = split('=',$Foilsubs[$j]); + $submission = &Apache::lonnet::unescape($submission); + $response_data{$foilid.' submission'}=$submission; + $response_data{$foilid.' award'}=$correct; + } + $worksheet->write($rows_output,$cols_output++,$student); + $worksheet->write($rows_output,$cols_output++, + &Apache::lonstathelpers::calc_serial($time),$format->{'date'}); + $worksheet->write($rows_output,$cols_output++,$award); + $worksheet->write($rows_output,$cols_output++,$tries); + foreach my $foilid (@$Foils) { + $worksheet->write($rows_output,$cols_output++, + $response_data{$foilid.' submission'}); + $worksheet->write($rows_output,$cols_output++, + $response_data{$foilid.' award'}); + } + $rows_output++; + $cols_output = 0; + } + return; +} + sub build_foil_index { my ($ORdata) = @_; - return if (! exists($ORdata->{'Foils'})); - my %Foildata = %{$ORdata->{'Foils'}}; + return if (! exists($ORdata->{'_Foils'})); + my %Foildata = %{$ORdata->{'_Foils'}}; my @Foils = sort(keys(%Foildata)); my %Concepts; foreach my $foilid (@Foils) { - push(@{$Concepts{$Foildata{$foilid}->{'Concept'}}}, + push(@{$Concepts{$Foildata{$foilid}->{'_Concept'}}}, $foilid); } undef(@Foils); @@ -174,18 +1453,26 @@ sub build_foil_index { eight => 8, nine => 9, ten => 10,); - my $a1 = $a; - my $b1 = $b; - if (exists($Numbers{lc($a)})) { - $a1 = $Numbers{lc($a)}; + my $a1 = lc($a); + my $b1 = lc($b); + if (exists($Numbers{$a1})) { + $a1 = $Numbers{$a1}; } - if (exists($Numbers{lc($b)})) { - $b1 = $Numbers{lc($b)}; + if (exists($Numbers{$b1})) { + $b1 = $Numbers{$b1}; + } + if (($a1 =~/^\d+$/) && ($b1 =~/^\d+$/)) { + return $a1 <=> $b1; + } else { + return $a1 cmp $b1; } - $a1 cmp $b1; }; my @Concepts; foreach my $concept (sort $sortfunction (keys(%Concepts))) { + if (! defined($Concepts{$concept})) { + $Concepts{$concept}=[]; +# next; + } push(@Concepts,{ name => $concept, foils => [@{$Concepts{$concept}}]}); push(@Foils,(@{$Concepts{$concept}})); @@ -218,18 +1505,18 @@ sub build_foil_index { if (@Concepts > 1) { $table .= ''. - (' 'x4).' | '. - ''.$option.' | '. + ''. + ''.('*'x3).''.' | '. + ''.&HTML::Entities::encode($option,'<>&"').' | '. "
'.$plotlink.' | '.$extrakey." |
'. + ''.('*'x4).' | '. + ''.&HTML::Entities::encode($foil,'<>&"'). + (' 'x2).$extra_data->{$foil}.' | '. + "
".$plothtml.' | '.
- "Start Time: ".$startdateform." ". - "End Time : "." ".$enddateform." ". - 'Plot Title :'.(" "x3). - ' '.$extratable. - " |
'.&mt('Sections').' | '; @@ -625,171 +1638,135 @@ sub CreateInterface { ## ## $Str .= '';
- { # These braces are here to organize the code, not scope it.
- {
- $Str .= ' '; - } - { - $Str .= ' '; - } - { - $Str .= ' '; + ## + my $analyze_selector = ''; + $Str .= ' '.$/; + ## + my $numplots_selector = ' '; + $Str .= ' | ';
##
##
$Str .= '
'. - ''. - ' | '. - ''.$res->{'title'}.' '; - if ($partdata->{'option'} > 1) { - $seq_str .= &mt('response').' '.$respid; - } - $seq_str .= " |
  | '.$seq->{'title'}.' | '. - "