[LON-CAPA-cvs] cvs: loncom /interface/statistics lonproblemanalysis.pm

matthew lon-capa-cvs@mail.lon-capa.org
Wed, 10 Nov 2004 21:23:10 -0000


This is a MIME encoded message

--matthew1100121790
Content-Type: text/plain

matthew		Wed Nov 10 16:23:10 2004 EDT

  Modified files:              
    /loncom/interface/statistics	lonproblemanalysis.pm 
  Log:
  Finished time analysis for numerical responses.  Things seem to work but I
  am seeing strange results.
  
  
--matthew1100121790
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20041110162310.txt"

Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.103 loncom/interface/statistics/lonproblemanalysis.pm:1.104
--- loncom/interface/statistics/lonproblemanalysis.pm:1.103	Wed Nov 10 11:56:39 2004
+++ loncom/interface/statistics/lonproblemanalysis.pm	Wed Nov 10 16:23:10 2004
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonproblemanalysis.pm,v 1.103 2004/11/10 16:56:39 matthew Exp $
+# $Id: lonproblemanalysis.pm,v 1.104 2004/11/10 21:23:10 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -193,35 +193,105 @@
          $Apache::lonstatistics::enrollment_status,
          $resource->{'symb'},$respid);
     #
+    $problem_analysis->{'answercomputed'} = 1;
+    if ($problem_analysis->{'answercomputed'}) {
+        my $answers = 
+            &Apache::lonstathelpers::GetStudentAnswers($r,$problem,$students,
+                                                       'Statistics',
+                                                       'stats_status');
+        $r->print(&numerical_one_dimensional_plot($r,600,150,$answers));
+    }
+    my $analysis_html = '<table>';
     for (my $plot_num = 1;$plot_num<=$ENV{'form.NumPlots'};$plot_num++) {
         my $restriction_function;
-        $restriction_function = sub {($_[0]->{'tries'} == $plot_num?1:0)};
+        my $header_message;
+        my $stats_message;
+        my $post_message; # passed through &mt sooner rather than later
+        my $no_data_message;
+        my @extra_data;
+        if ($ENV{'form.AnalyzeOver'} eq 'tries') {
+            $restriction_function = sub {($_[0]->{'tries'} == $plot_num?1:0)};
+            $header_message = 'Attempt [_1]';
+            $stats_message = 
+                '[_1] submissions, [_2] correct, [_3] incorrect';
+            $post_message = '';
+            $no_data_message = 'No data exists for attempt [_1]';
+        } else {
+            my $starttime = &Apache::lonhtmlcommon::get_date_from_form
+                ('startdate_'.$plot_num);
+            my $endtime = &Apache::lonhtmlcommon::get_date_from_form
+                ('enddate_'.$plot_num);
+            ($starttime,$endtime) = &ensure_start_end_times
+                ($starttime,$endtime,
+                 &get_time_from_row($response_data->[0]),
+                 &get_time_from_row($response_data->[-1]),
+                 $plot_num);
+            $header_message = 'Data from [_2] to [_3]';
+            $extra_data[0] = &Apache::lonlocal::locallocaltime($starttime);
+            $extra_data[1] = &Apache::lonlocal::locallocaltime($endtime);
+            #
+            $stats_message = 
+                '[_1] submissions from [_4] students, [_2] correct, [_3] incorrect';
+            #
+            $post_message = 
+                &mt('Start time: [_1]',
+                    &Apache::lonhtmlcommon::date_setter
+                    ('Statistics','startdate_'.$plot_num,$starttime)).
+                '<br />'.
+                &mt('End time: [_1]',
+                    &Apache::lonhtmlcommon::date_setter
+                    ('Statistics','enddate_'.$plot_num,$endtime));
+            $restriction_function = 
+                sub { 
+                    my $t = $_[0]->{'timestamp'};
+                    if ($t >= $starttime && $t < $endtime) {
+                        return 1;
+                    } else { 
+                        return 0;
+                    }
+                };
+            $no_data_message = 'No data for [_2] to [_3]';
+        }
         #
         my ($correct,$intervals,$answers) = 
             &numerical_response_determine_intervals($r,$resource,$partid,
                                                     $respid,$students);
         if ($c->aborted()) { return; };
         #
-        my $responses = &classify_response_data($response_data,
-                                                $correct,
-                                                $restriction_function);
-        my $student_count = $responses->{'_students'};
-        my $correct_count = $responses->{'_correct'};
-        my $total_count   = $responses->{'_count'};
-        my $max           = $responses->{'_max'};
-        #
-        my $analysis_html = '<h2>'.&mt('Attempt [_1]',$plot_num).'</h2>';
-        $analysis_html.= &numerical_one_dimensional_plot($r,600,150,
-                                                         scalar(@$students),
-                                                         $answers);
-        $analysis_html.= '<table><tr>'.
-            '<td valign="top" align="center">'.
-            &numerical_plot_percent($r,$responses).'</td>'.
-            '<td align="center" valign="top">'.
-            &numerical_plot_differences($r,$responses).'</td>'.
-            '</tr>'.$/.'</table>';
-        $r->print($analysis_html);
+        my $responses = &numerical_classify_responses($response_data,
+                                                      $correct,
+                                                      $restriction_function);
+        if ($responses->{'_count'} == 0) {
+            $analysis_html.= 
+                '<tr><td colspan="2"><font size="+1"><b>'.
+                &mt($no_data_message,$plot_num,@extra_data).
+                '</b></font></td></tr>';
+        } else {
+            $analysis_html.= 
+                '<tr><td colspan="2" align="center"><font size="+1"><b>'.
+                &mt($header_message,$plot_num,@extra_data).
+                '</b></font></td></tr>'.
+                '<tr><td colspan="2" align="center">'.
+                &mt($stats_message,
+                    $responses->{'_count'},
+                    $responses->{'_correct'},
+                    $responses->{'_count'}-$responses->{'_correct'},
+                    $responses->{'_students'},
+                    @extra_data).
+                    '</td></tr>'.
+                    '<tr>'.'<td valign="top" align="center">'.
+                    &numerical_plot_percent($r,$responses).'</td>'.
+                    '<td align="center" valign="top">'.
+                    &numerical_plot_differences($r,$responses).'</td>'.
+                    '</tr>';
+        }
+        if ($post_message ne '') {
+            $analysis_html .=
+                '<tr><td colspan="2">'.$post_message.'</td></tr>';
+        }
     }
+    $analysis_html.='</table>';
+    $r->print($analysis_html);
     #
     return;
 }
@@ -243,9 +313,9 @@
     #
     my @bins;
     if ($minbin < 1) {
-        @bins = (0.1, ".5",1,1.5,2,2.5,3,4,5,10,20,50,100);        
+        @bins = ('0.1','0.5','1.0','1.5','2.0','2.5','3.0','4.0','5.0',10,20,50,100);        
     } elsif ($minbin < 2) {
-        @bins = (0.5,1,1.5,2,2.5,3,4,5,10,20,50,100);
+        @bins = ('0.5','1.0','1.5','2.0','2.5','3.0','4.0','5.0',10,20,50,100);
     } elsif ($minbin < 5) {
         @bins = (1,2,3,4,5,10,25,50,75,100,200);
     } elsif ($minbin < 10) {
@@ -257,53 +327,37 @@
     #
     my @correct;
     my @incorrect;
+    my @count;
     while (my ($interval,$submissions) = each(%$responses)) {
         next if ($interval =~ /^_/);
         my ($ans,$ans_low,$ans_high) = split(" ",$interval);
-        while (my ($submission,$count) = each(%$submissions)) {
+        while (my ($submission,$counts) = each(%$submissions)) {
+            my ($correct_count,$incorrect_count) = @$counts;
             my $scaled_value = abs(($submission-$ans)/$ans);
             my $bin=0;
             for ($bin=0;$bin<$#bins;$bin++) { # not <= for a reason
                 last if ($bins[$bin]>$scaled_value);
             }
-            if (($submission <= $ans_high) && ($submission >= $ans_low)) {
-                $correct[$bin]+=$count;
-            } else {
-                $incorrect[$bin]+=$count;
-            }
+            $correct[$bin]+=$correct_count;
+            $incorrect[$bin]+=$incorrect_count;
+            $count[$bin]+=$correct_count+$incorrect_count;
         }
     }
     #
+    my @plot_correct;
+    my @plot_incorrect;
     for (my $i=0;$i<=$#bins;$i++) {
-        if (! defined(  $correct[$i])) {   $correct[$i]=0;}
-        if (! defined($incorrect[$i])) { $incorrect[$i]=0;}
-        $correct[$i]*=100/$total;
-        $incorrect[$i]*=100/$total;
+        $plot_correct[$i] = $correct[$i]*100/$total;
+        $plot_incorrect[$i] = $incorrect[$i]*100/$total;
     }
     my $title = &mt('Distribution by Percent');
     my $graph = &Apache::loncommon::DrawBarGraph
         ($title,'Percent difference from correct','Number of answers',
-         100,['#33FF00','#FF3300'],\@labels,\@correct,\@incorrect,
+         100,['#33FF00','#FF3300'],\@labels,\@plot_correct,\@plot_incorrect,
          {xskip=>1});
     #
-    my $table = $graph.'<table><tr><th>'.&mt('Bar').'</th>'.
-        '<th colspan="3">'.&mt('Range').'</th>';
-    for (my $i=0;$i<=$#bins;$i++) {
-        my $lownum;
-        if ($i == 0) {
-            $lownum = 0;
-        } else {
-            $lownum = $bins[$i-1];
-        }
-        my $highnum = $bins[$i];
-        $table .= 
-            '<tr>'.
-            '<td>'.$labels[$i].'</td>'.
-            '<td align="right">'.$lownum.'</td>'.
-            '<td>&nbsp;-&nbsp;</td>'.
-            '<td align="right">'.$highnum.'</td>'.'</tr>'.$/;
-    }
-    $table.= '</table>'.$/;
+    my $table = $graph.$/.
+        &numerical_bin_table(\@bins,\@labels,\@incorrect,\@correct,\@count).$/;
     return $table;
 }
 
@@ -339,52 +393,122 @@
     #
     my @correct;
     my @incorrect;
+    my @count;
     while (my ($interval,$submissions) = each(%$responses)) {
         next if ($interval =~ /^_/);
         my ($ans,$ans_low,$ans_high) = split(" ",$interval);
-        while (my ($submission,$count) = each(%$submissions)) {
+        while (my ($submission,$counts) = each(%$submissions)) {
+            my ($correct_count,$incorrect_count) = @$counts;
             my $value = abs($submission-$ans);
             my $bin=0;
             for ($bin=0;$bin<$#bins;$bin++) { # not <= for a reason
                 last if ($bins[$bin]>$value);
             }
-            if (($submission <= $ans_high) && ($submission >= $ans_low)) {
-                $correct[$bin]+=$count;
-            } else {
-                $incorrect[$bin]+=$count;
-            }
+            $correct[$bin]+=$correct_count;
+            $incorrect[$bin]+=$incorrect_count;
+            $count[$bin]+=$correct_count+$incorrect_count;
         }
     }
     #
+    my @plot_correct;
+    my @plot_incorrect;
     for (my $i=0;$i<=$#bins;$i++) {
-        if (! defined(  $correct[$i])) {   $correct[$i]=0;}
-        if (! defined($incorrect[$i])) { $incorrect[$i]=0;}
-        $correct[$i]*=100/$total;
-        $incorrect[$i]*=100/$total;
+        $plot_correct[$i]   =   $correct[$i]*100/$total;
+        $plot_incorrect[$i] = $incorrect[$i]*100/$total;
     }
     my $title = &mt('Distribution by Magnitude');
     my $graph = &Apache::loncommon::DrawBarGraph
         ($title,'magnitude difference from correct','Number of answers',
-         100,['#33FF00','#FF3300'],\@labels,\@correct,\@incorrect,{xskip=>1});
+         100,['#33FF00','#FF3300'],\@labels,\@plot_correct,\@plot_incorrect,
+         {xskip=>1});
     #
-    my $table = $graph.'<table><tr><th>'.&mt('Bar').'</th>'.
-        '<th colspan="3">'.&mt('Range').'</th>';
-    for (my $i=0;$i<=$#bins;$i++) {
+    my $table = $graph.$/.
+        &numerical_bin_table(\@bins,\@labels,\@incorrect,\@correct,\@count).$/;
+    return $table;
+}
+
+sub numerical_classify_responses {
+    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)) {
+            my $submission = $subm{'submission'};
+            $students{$subm{'student'}}++;
+            if (&numerical_submission_is_correct($subm{'award'})) { 
+                $submission_data{'_correct'}++;
+                $submission_data{'_count'}++;
+                $submission_data{$subm{'correct'}}->{$submission}->[0]++;
+            } elsif (&numerical_submission_is_incorrect($subm{'award'})) { 
+                $submission_data{'_count'}++;
+                $submission_data{$subm{'correct'}}->{$submission}->[1]++;
+            }
+            my $value = 
+                $submission_data{$subm{'correct'}}->{$submission}->[0]+ 
+                $submission_data{$subm{'correct'}}->{$submission}->[1];
+            if ($max < $value) { $max = $value; }
+        }
+    }
+    $submission_data{'_max'} = $max;
+    $submission_data{'_students'}=scalar(keys(%students));
+    return \%submission_data;
+}
+
+sub numerical_submission_is_correct {
+    my ($award) = @_;
+    if ($award =~ /^(APPROX_ANS|EXACT_ANS)$/) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+sub numerical_submission_is_incorrect {
+    my ($award) = @_;
+    if ($award =~ /^(INCORRECT)$/) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+sub numerical_bin_table {
+    my ($bins,$labels,$incorrect,$correct,$count)=@_;
+    my $table = 
+        '<table><tr><th>'.&mt('Bar').'</th>'.
+        '<th colspan="3">'.&mt('Range').'</th>'.
+        '<th>'.&mt('Incorrect').'</th>'.
+        '<th>'.&mt('Correct').'</th>'.
+        '<th>'.&mt('Count').'</th>'.
+        '</tr>'.$/;
+    for (my $i=0;$i<scalar(@{$bins});$i++) {
         my $lownum;
         if ($i == 0) {
             $lownum = 0;
         } else {
-            $lownum = $bins[$i-1];
+            $lownum = $bins->[$i-1];
         }
-        my $highnum = $bins[$i];
+        my $highnum = $bins->[$i];
         $table .= 
             '<tr>'.
-            '<td>'.$labels[$i].'</td>'.
+            '<td>'.$labels->[$i].'</td>'.
             '<td align="right">'.$lownum.'</td>'.
             '<td>&nbsp;-&nbsp;</td>'.
-            '<td align="right">'.$highnum.'</td>'.'</tr>'.$/;
+            '<td align="right">'.$highnum.'</td>'.
+            '<td align="right">'.$incorrect->[$i].'</td>'.
+            '<td align="right">'.$correct->[$i].'</td>'.
+            '<td align="right">'.$count->[$i].'</td>'.
+            '</tr>'.$/;
     }
-    $table.= '</table>'.$/;
+    $table.= '</table>';
     return $table;
 }
 
@@ -392,7 +516,7 @@
     my ($r,$resource,$partid,$respid,$students)=@_;
     my $c = $r->connection();
     #
-    # FIX ME: Need progress dialog updates
+    # FIX ME: May need progress dialog updates
     #
     # Read in the cache (if it exists) before we start timing things.
     &Apache::lonstathelpers::ensure_proper_cache($resource->{'symb'});
@@ -424,14 +548,20 @@
     return ($correct,\%intervals,\%answers);
 }
 
+#
+# Inputs: $r, $width, $height, $data
+#         $n = number of students
+#         $data = hashref of $answer => $frequency pairs
 sub numerical_one_dimensional_plot {
-    my ($r,$width,$height,$n,$data)=@_;
+    my ($r,$width,$height,$data)=@_;
     #
     # Compute data -> image scaling factors
     my $max_y = 0;
     my $min_x = undef;
     my $max_x = undef;
+    my $n = 0;
     while (my ($answer,$count) = each(%$data)) {
+        $n+=$count;
         $max_y = $count if ($max_y < $count);
         if (! defined($min_x) || $answer < $min_x) {
             $min_x = $answer;
@@ -965,7 +1095,6 @@
         if (&$function(\%subm)) {
             $students{$subm{'student'}}++;
             $submission_data{'_count'}++;
-            
             if (&submission_is_correct($subm{'award'})) { 
                 $submission_data{'_correct'}++;
             }

--matthew1100121790--