\n";
- my @Plots;
- for (my $i=$mintries;$i<=$maxtries;$i++) {
- my $minstu = $PlotData[$i]->{'total'}->[0];
- my $maxstu = $PlotData[$i]->{'total'}->[0];
- foreach my $count (@{$PlotData[$i]->{'total'}}) {
- if ($minstu > $count) {
- $minstu = $count;
- }
- if ($maxstu < $count) {
- $maxstu = $count;
- }
- }
- $maxstu = 0 if (! $maxstu);
- $minstu = 0 if (! $minstu);
- my $title;
- if ($maxstu == $minstu) {
- $title = 'Attempt '.$i.', '.$maxstu.' students';
- } else {
- $title = 'Attempt '.$i.', '.$minstu.'-'.$maxstu.' students';
- }
- my $graphlink = &Apache::loncommon::DrawGraph($title,
- $xlabel,
- 'Percent Correct',
- 100,
- $PlotData[$i]->{'good'},
- $PlotData[$i]->{'bad'});
- push(@Plots,$graphlink);
- }
- #
- # Should this be something the user can set? Too many dialogs!
- my $plots_per_row = 2;
- while (my $plotlink = shift(@Plots)) {
- $table .= '
'.$plotlink.'
';
- for (my $i=1;$i<$plots_per_row;$i++) {
- if ($plotlink = shift(@Plots)) {
- $table .= '
'.$plotlink.'
';
- } else {
- $table .= '
';
+ #
+ # Create Foil Plots
+ my $data_count = $response_data{'_total'}->[$try];
+ my $correct = $response_data{'_correct'}->[$try];
+ $correct |= 0;
+ my @Datasets;
+ foreach my $option ('_correct',@{$ORdata->{'_Options'}}) {
+ next if (! exists($foil_plot[$try]->{$option}));
+ push(@Datasets,$foil_plot[$try]->{$option});
+ }
+ #
+ # Put a blank in the data set between concepts
+ for (my $set =0;$set<=$#Datasets;$set++) {
+ my @Data = @{$Datasets[$set]};
+ my $idx = 0;
+ foreach my $concept (@{$Concepts}) {
+ foreach my $foilid (@{$concept->{'foils'}}) {
+ $Datasets[$set]->[$idx++]=shift(@Data);
+ }
+ if ($concept->{'name'} ne $Concepts->[-1]->{'name'}) {
+ $Datasets[$set]->[$idx++] = 0;
+ }
+ }
+ }
+ #
+ # Set up the labels needed for the bar graph
+ my @Labels;
+ my $idx = 1;
+ foreach my $concept (@{$Concepts}) {
+ foreach my $foilid (@{$concept->{'foils'}}) {
+ push(@Labels,$idx++);
}
+ push(@Labels,'');
}
- $table .= "
\n";
+ #
+ my $correct_graph = &Apache::loncommon::DrawBarGraph
+ ('Correct Statements','Statement','% Answered Correct',
+ 100,$plotcolors,\@Labels,$Datasets[0],{xskip=>1});
+
+ #
+ #
+ next if (! defined($Datasets[0]));
+ for (my $i=0; $i< scalar(@{$Datasets[0]});$i++) {
+ $Datasets[0]->[$i]=0;
+ }
+ my $count = $response_data{'_total'}->[$try] -
+ $response_data{'_correct'}->[$try];
+ my $incorrect_graph = &Apache::loncommon::DrawBarGraph
+ ('Incorrect Statements','Statement','% Chosen Incorrectly',
+ 100,$plotcolors,\@Labels,@Datasets,{xskip=>1});
+ $analysis_html.=
+ '
\n";
+ $table .= '';
+ #
return $table;
}
-sub analyze_option_data_by_time {
- my ($PerformanceData,$begin_index,$end_index,$description,@Concepts) = @_;
- my %TimeData;
- #
- # Get the start and end times for this segment of the plot
- my $starttime = $PerformanceData->[$begin_index]->[2];
- my $endtime = $PerformanceData->[$end_index ]->[2];
- #
- # Compute the number getting the foils correct or incorrects
- for (my $i=$begin_index;$i<=$end_index;$i++) {
- my $row = $PerformanceData->[$i];
- next if (! defined($row));
- my ($grading,$submission,$time,$tries) = @$row;
- my @Foilgrades = split('&',$grading);
- my @Foilsubs = split('&',$submission);
- foreach my $foilgrade (@Foilgrades) {
- my ($foilid,$correct) = split('=',$foilgrade);
- if ($correct) {
- $TimeData{$foilid}->{'correct'}++;
+sub OR_Foil_Time_Analysis {
+ my ($processed_time_data,$correct,$data_count,$student_count,
+ $ORdata,$Foils,$Concepts) = @_;
+ if ($data_count <= 0) {
+ return ('
'.&mt('There is no data to plot').'
','');
+ }
+ my $analysis_html;
+ my @plotdata;
+ my @labels;
+ foreach my $concept (@{$Concepts}) {
+ foreach my $foil (@{$concept->{'foils'}}) {
+ push(@labels,scalar(@labels)+1);
+ my $total = $processed_time_data->{$foil}->{'_total'};
+ if ($total == 0) {
+ push(@{$plotdata[0]},0);
} else {
- $TimeData{$foilid}->{'incorrect'}++;
+ push(@{$plotdata[0]},
+ 100 * $processed_time_data->{$foil}->{'_correct'} / $total);
+ }
+ my $total_incorrect = $total - $processed_time_data->{$foil}->{'_correct'};
+ for (my $i=0;$i{'_Options'}});$i++) {
+ my $option = $ORdata->{'_Options'}->[$i];
+ if ($total_incorrect == 0) {
+ push(@{$plotdata[$i+1]},0);
+ } else {
+ push(@{$plotdata[$i+1]},
+ 100 * $processed_time_data->{$foil}->{$option} / $total_incorrect);
+ }
}
}
+ # Put in a blank one
+ push(@labels,'');
+ push(@{$plotdata[0]},0);
+ for (my $i=0;$i{'_Options'}});$i++) {
+ push(@{$plotdata[$i+1]},0);
+ }
}
#
- # Compute the total and percent correct
- my @Plotdata1;
- my @Plotdata2;
- foreach my $concept (@Concepts) {
- my ($correct,$incorrect,$total);
- foreach my $foilid (@{$concept->{'foils'}}) {
- if (! exists($TimeData{$foilid}->{'correct'})) {
- $TimeData{$foilid}->{'correct'} = 0;
- }
- if (! exists($TimeData{$foilid}->{'incorrect'})) {
- $incorrect = 0;
- $TimeData{$foilid}->{'incorrect'} = 0;
- }
- $correct += $TimeData{$foilid}->{'correct'};
- $incorrect += $TimeData{$foilid}->{'incorrect'};
- $total += $TimeData{$foilid}->{'correct'}+
- $TimeData{$foilid}->{'incorrect'};
- $TimeData{$foilid}->{'total'} = $TimeData{$foilid}->{'correct'} +
- $TimeData{$foilid}->{'incorrect'};
- my $percent;
- if ($TimeData{$foilid}->{'total'} == 0) {
- $percent = 0;
- } else {
- $percent = $TimeData{$foilid}->{'correct'} /
- $TimeData{$foilid}->{'total'};
+ # Create the plot
+ my $correct_plot = &Apache::loncommon::DrawBarGraph('Correct Statements',
+ 'Statement Number',
+ 'Percent Correct',
+ 100,
+ $plotcolors,
+ undef,
+ $plotdata[0],
+ {xskip=>1});
+ for (my $j=0; $j< scalar(@{$plotdata[0]});$j++) {
+ $plotdata[0]->[$j]=0;
+ }
+ my $incorrect_plot =
+ &Apache::loncommon::DrawBarGraph('Incorrect Statements',
+ 'Statement Number',
+ 'Incorrect Option Choice',
+ 100,
+ $plotcolors,
+ undef,
+ @plotdata,{xskip=>1});
+ return ($correct_plot,$incorrect_plot);
+}
+
+sub OR_Concept_Time_Analysis {
+ my ($processed_time_data,$correct,$data_count,$student_count,
+ $ORdata,$Concepts) = @_;
+ return '' if ($data_count == 0);
+ #
+ # Put the data in plottable form
+ my @plotdata;
+ foreach my $concept (@$Concepts) {
+ my ($total,$correct);
+ foreach my $foil (@{$concept->{'foils'}}) {
+ $total += $processed_time_data->{$foil}->{'_total'};
+ $correct += $processed_time_data->{$foil}->{'_correct'};
+ }
+ if ($total == 0) {
+ push(@plotdata,0);
+ } else {
+ push(@plotdata,100 * $correct / $total);
+ }
+ }
+ #
+ # Create the plot
+ return &Apache::loncommon::DrawBarGraph('Correct Concepts',
+ 'Concept Number',
+ 'Percent Correct',
+ 100,
+ $plotcolors,
+ undef,
+ \@plotdata,{xskip=>1});
+}
+
+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)) {
+ $processed_time_data{$foilid} += $href;
+ next;
}
- $TimeData{$foilid}->{'percent_corr'} = 100 * $percent;
- if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
- push (@Plotdata1, $TimeData{$foilid}->{'percent_corr'});
- push (@Plotdata2,100-$TimeData{$foilid}->{'percent_corr'});
+ while (my ($option,$value) = each(%$href)) {
+ $processed_time_data{$foilid}->{$option}+=$value;
}
}
- if ($ENV{'form.AnalyzeAs'} ne 'Foils') {
- if ($total == 0) {
- push (@Plotdata1,0);
- push (@Plotdata2,100);
- } else {
- push (@Plotdata1,100 * $correct / $total);
- push (@Plotdata2,100 * (1-$correct / $total));
- }
+ }
+ 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 (exists($Numbers{$b1})) {
+ $b1 = $Numbers{$b1};
+ }
+ if (($a1 =~/^\d+$/) && ($b1 =~/^\d+$/)) {
+ return $a1 <=> $b1;
+ } else {
+ 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 $xlabel;
- if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
- $xlabel = 'Foil Number';
+ # Build up the table of row labels.
+ my $table = '