'
+ .&mt('There are no students in the sections/groups selected.')
+ .'
'
+ );
}
+ #
+ my @CacheButtonHTML =
+ &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status');
$r->rflush();
- if (exists($ENV{'form.problemchoice'}) &&
- ! exists($ENV{'form.SelectAnother'})) {
- $r->print('');
- $r->print(' 'x5);
- $r->print('');
- $r->print(' 'x5);
- $r->print('');
- $r->print(' 'x5);
- $r->print('');
- $r->print('');
- $r->print(' 'x5);
+ #
+ my $problem_types = &analyzable_types();
+ if (exists($env{'form.problemchoice'}) &&
+ ! exists($env{'form.SelectAnother'})) {
+ foreach my $button (@SubmitButtons) {
+ if ($button->{'name'} eq 'break') {
+ $r->print(" \n");
+ } else {
+ $r->print('{'text'}).'" />');
+ $r->print(' 'x5);
+ }
+ }
+ foreach my $html (@CacheButtonHTML) {
+ $r->print($html.(' 'x5));
+ }
+ #
+
+ # This is commented out pending actual implementation of
+ # CSV and Excel output.
+ #$r->print(&Apache::lonstathelpers::submission_report_form
+ # ('problem_analysis'));
#
$r->print('');
+ $r->rflush();
#
- my ($symb,$part,$resid) = &get_problem_symb(
- &Apache::lonnet::unescape($ENV{'form.problemchoice'})
- );
- #
- my $resource = &get_resource_from_symb($symb);
- if (defined($resource)) {
- $r->print('
'.$resource->{'src'}.'
');
- my %Data = &get_problem_data($resource->{'src'});
- my $ORdata = $Data{$part.'.'.$resid};
- ##
- ## Render the problem
- my $base;
- ($base,undef) = ($resource->{'src'} =~ m|(.*/)[^/]*$|);
- $base = "http://".$ENV{'SERVER_NAME'}.$base;
- my $rendered_problem =
- &Apache::lonnet::ssi_body($resource->{'src'});
- $rendered_problem =~ s/<\s*form\s*/)|<\/nop>|g;
- $r->print('
'.
- ''.
- $rendered_problem.
- '
');
- ##
- ## Analyze the problem
- my $PerformanceData =
- &Apache::loncoursedata::get_optionresponse_data
- (\@Students,$symb,$resid);
- if (defined($PerformanceData) &&
- ref($PerformanceData) eq 'ARRAY') {
- if ($ENV{'form.AnalyzeOver'} eq 'Tries') {
- my $analysis_html = &tries_analysis($PerformanceData,
- $ORdata);
- $r->print($analysis_html);
- } elsif ($ENV{'form.AnalyzeOver'} eq 'Time') {
- my $analysis_html = &time_analysis($PerformanceData,
- $ORdata);
- $r->print($analysis_html);
- } else {
- $r->print('
'.
- &mt('The analysis you have selected is '.
- 'not supported at this time').
- '
');
- }
- } else {
- $r->print('
'.
- &mt('There is no student data for this problem.').
- '
');
- }
- } else {
+ # Determine which problem we are to analyze
+ my ($navmap,$current_problem) = &get_current_problem(); # need to retrieve $navmap
+ # to support $resource->* calls
+ # for src and compTitle (below)
+ #
+ # Store the current problem choice and send it out in the form
+ $env{'form.problemchoice'} =
+ &Apache::lonstathelpers::make_target_id($current_problem);
+ $r->print('');
+ #
+ if (! defined($current_problem->{'resource'})) {
$r->print('resource is undefined');
+ } else {
+ my $resource = $current_problem->{'resource'};
+ $r->print('
\n";
- return $analysis_html;
+ #
+ return '' if (! scalar(keys(%column)));
+ #
+ my $grand_total = 0;
+ my %count_per_foil;
+ while (my ($foil,$bar) = each (%column)) {
+ my $bar_total = 0;
+ for (my $j=0;$j[$bar];
+ }
+ next if ($bar_total == 0);
+ for (my $j=0;$j[$bar] =
+ sprintf('%2f',$dataset[$j]->[$bar]/$bar_total * 100);
+ }
+ $count_per_foil{$foil}=' ( '.$bar_total.' )';
+ $grand_total += $bar_total;
+ }
+ if ($grand_total == 0) {
+ return ('',undef);
+ }
+ my @empty_row = ();
+ foreach (@{$dataset[0]}) {
+ push(@empty_row,0);
+ }
+ #
+ my $xlabel = &mt('Correct Foil');
+ my $ylabel = &mt('foils chosen Incorrectly');
+ my $graph = &Apache::loncommon::DrawBarGraph
+ ($title,$xlabel,$ylabel,
+ 100,$plotcolors,\@labels,\@empty_row,@dataset);
+ return ($graph,\%count_per_foil);
}
-sub Tries_Concept_Analysis {
- my ($mintries,$maxtries,$Concepts,$respdat,$ORdata) = @_;
- my %ResponseData = %$respdat;
- my $analysis_html = "
\n";
- #
- # Compute the data neccessary to make the plots
- my @PlotData;
- # Concept analysis
- #
- # Note: we do not bother with characterizing the students incorrect
- # answers at the concept level because an incorrect answer for one foil
- # may be a correct answer for another foil.
- my %ConceptData;
- foreach my $concept (@{$Concepts}) {
- for (my $i=$mintries;$i<=$maxtries;$i++) {
- #
- # Gather the per-attempt data
- my $cdata = $ConceptData{$concept}->[$i];
- foreach my $foilid (@{$concept->{'foils'}}) {
- $cdata->{'_correct'} +=
- $ResponseData{$foilid}->[$i]->{'_correct'};
- $cdata->{'_total'} +=
- $ResponseData{$foilid}->[$i]->{'_total'};
- }
- push (@{$PlotData[$i]->{'_total'}},$cdata->{'_total'});
- if ($cdata->{'_total'} == 0) {
- push (@{$PlotData[$i]->{'_correct'}},0);
- } else {
- push (@{$PlotData[$i]->{'_correct'}},
- 100*$cdata->{'_correct'}/$cdata->{'_total'});
- }
+
+#########################################################
+#########################################################
+##
+## Misc routines
+##
+#########################################################
+#########################################################
+
+# if $correct is a hash ref, it is assumed to be indexed by student names.
+# the values are assumed to be hash refs with a key of 'answer'.
+sub classify_response_data {
+ my ($full_row_data,$correct,$function) = @_;
+ my %submission_data;
+ my %students;
+ my $max=0;
+ foreach my $row (@$full_row_data) {
+ my %subm = &hashify_attempt($row);
+ if (ref($correct) eq 'HASH') {
+ $subm{'correct'} = $correct->{$subm{'student'}};
+ } else {
+ $subm{'correct'} = $correct;
+ }
+ $subm{'submission'} =~ s/=\d+\s*$//;
+ if (&$function(\%subm)) {
+ $students{$subm{'student'}}++;
+ $submission_data{'_count'}++;
+ if (&submission_is_correct($subm{'award'})) {
+ $submission_data{'_correct'}++;
+ }
+
+ if($max<++$submission_data{$subm{'correct'}}->{$subm{'submission'}}) {
+ $max=$submission_data{$subm{'correct'}}->{$subm{'submission'}};
+ }
}
}
+ $submission_data{'_max'} = $max;
+ $submission_data{'_students'}=scalar(keys(%students));
+ return \%submission_data;
+}
+
+
+#########################################################
+#########################################################
+##
+## Option Response Routines
+##
+#########################################################
+#########################################################
+sub OptionResponseAnalysis {
+ my ($r,$problem,$problem_data,$Students) = @_;
+ my ($resource,$respid) = ($problem->{'resource'},
+ $problem->{'respid'});
+ # Note: part data is not needed.
+ my $PerformanceData = &Apache::loncoursedata::get_response_data
+ ([&Apache::lonstatistics::get_selected_sections()],
+ [&Apache::lonstatistics::get_selected_groups()],
+ $Apache::lonstatistics::enrollment_status,
+ $resource->symb,$respid);
+ if (! defined($PerformanceData) ||
+ ref($PerformanceData) ne 'ARRAY' ) {
+ $r->print('
'
+ .&mt('There is no student data for this problem.')
+ .'
\n";
- return $analysis_html;
+ my %lt = &Apache::lonlocal::texthash(
+ 'title' => 'Correct Concepts',
+ 'xlabel' => 'Concept Number',
+ 'ylabel' => 'Percent Correct');
+ return &Apache::loncommon::DrawBarGraph($lt{'title'},
+ $lt{'xlabel'},
+ $lt{'ylabel'},
+ 100,
+ $plotcolors,
+ undef,
+ \@plotdata,{xskip=>1});
}
-sub Concept_Time_Analysis {
- my ($PerformanceData,$ORdata,$Concepts,$interval) = @_;
- my $analysis_html;
- ##
- ## Determine starttime, endtime, startindex, endindex
- my ($begin_index,$end_index) = ($interval->{'begin_index'},
- $interval->{'end_index'});
- my %TimeData;
- #
- # Compute the number getting the foils correct or incorrects
- for (my $j=$begin_index;$j<=$end_index;$j++) {
- my $row = $PerformanceData->[$j];
- next if (! defined($row));
- my %Row = &Process_Row($row);
- while (my ($foilid,$href) = each(%Row)) {
+sub OR_time_process_data {
+ my ($performance_data,$begin_index,$end_index)=@_;
+ my %processed_time_data;
+ my %distinct_students;
+ my ($correct,$data_count);
+ if (($begin_index == $end_index) &&
+ ($end_index != scalar(@$performance_data)-1)) {
+ return undef;
+ }
+ # Be sure we include the last one if we are asked for it.
+ # That we have to correct here (and not when $end_index is
+ # given a value) should probably be considered a bug.
+ if ($end_index == scalar(@$performance_data)-1) {
+ $end_index++;
+ }
+ my $count;
+ for (my $i=$begin_index;$i<$end_index;$i++) {
+ my $attempt = $performance_data->[$i];
+ $count++;
+ next if (! defined($attempt));
+ my %attempt = &Process_OR_Row($attempt);
+ $data_count++;
+ $correct += $attempt{'_correct'};
+ $distinct_students{$attempt->[&Apache::loncoursedata::RD_student_id()]}++;
+ while (my ($foilid,$href) = each(%attempt)) {
if (! ref($href)) {
- $TimeData{$foilid} += $href;
+ $processed_time_data{$foilid} += $href;
next;
}
while (my ($option,$value) = each(%$href)) {
- $TimeData{$foilid}->{$option}+=$value;
+ $processed_time_data{$foilid}->{$option}+=$value;
}
}
}
- #
- # Put the data in plottable form
- my @Plotdata;
- foreach my $concept (@$Concepts) {
- my ($total,$correct);
- foreach my $foil (@{$concept->{'foils'}}) {
- $total += $TimeData{$foil}->{'_total'};
- $correct += $TimeData{$foil}->{'_correct'};
+ return (\%processed_time_data,$correct,$data_count,
+ scalar(keys(%distinct_students)));
+}
+
+sub build_foil_index {
+ my ($ORdata) = @_;
+ 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'}}},
+ $foilid);
+ }
+ undef(@Foils);
+ # Having gathered the concept information in a hash, we now translate it
+ # into an array because we need to be consistent about order.
+ # Also put the foils in order, too.
+ my $sortfunction = sub {
+ my %Numbers = (one => 1,
+ two => 2,
+ three => 3,
+ four => 4,
+ five => 5,
+ six => 6,
+ seven => 7,
+ eight => 8,
+ nine => 9,
+ ten => 10,);
+ my $a1 = lc($a);
+ my $b1 = lc($b);
+ if (exists($Numbers{$a1})) {
+ $a1 = $Numbers{$a1};
}
- if ($total == 0) {
- push(@Plotdata,0);
+ if (exists($Numbers{$b1})) {
+ $b1 = $Numbers{$b1};
+ }
+ if (($a1 =~/^\d+$/) && ($b1 =~/^\d+$/)) {
+ return $a1 <=> $b1;
} else {
- push(@Plotdata,100 * $correct / $total);
+ return $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}}));
}
#
- # Create the plot
- my $title = ($end_index - $begin_index).' submissions';
- my $correctplot = &Apache::loncommon::DrawGraph($title,
- 'Concept Number',
- 'Percent Correct',
- 100,
- $plotcolors,
- \@Plotdata);
- $analysis_html.='