\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 $graph = &Apache::loncommon::DrawBarGraph
+ ($title,'Correct Foil','foils chosen Incorrectly',
+ 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;
+ return &Apache::loncommon::DrawBarGraph('Correct Concepts',
+ 'Concept Number',
+ 'Percent Correct',
+ 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.='