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

matthew lon-capa-cvs@mail.lon-capa.org
Fri, 29 Oct 2004 15:27:39 -0000


This is a MIME encoded message

--matthew1099063659
Content-Type: text/plain

matthew		Fri Oct 29 11:27:39 2004 EDT

  Modified files:              
    /loncom/interface/statistics	lonproblemanalysis.pm 
  Log:
  Radiobutton response works for concepts, computed answers, and the much
  more common incarnations.
  Removed some dead code.
  More to be done.
  
  
--matthew1099063659
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20041029112739.txt"

Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.96 loncom/interface/statistics/lonproblemanalysis.pm:1.97
--- loncom/interface/statistics/lonproblemanalysis.pm:1.96	Wed Oct 27 13:47:13 2004
+++ loncom/interface/statistics/lonproblemanalysis.pm	Fri Oct 29 11:27:39 2004
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonproblemanalysis.pm,v 1.96 2004/10/27 17:47:13 matthew Exp $
+# $Id: lonproblemanalysis.pm,v 1.97 2004/10/29 15:27:39 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -148,9 +148,9 @@
                                         $problem_data,
                                         \@Students);
             } elsif ($current_problem->{'resptype'} eq 'radiobutton') {
-                &RadioResponseAnalysis($r,$current_problem,
-                                       $problem_data,
-                                       \@Students);
+                &radio_response_analysis($r,$current_problem,
+                                         $problem_data,
+                                         \@Students);
             } elsif ($current_problem->{'resptype'} eq 'numerical') {
                 ## 
                 ## analyze all responses of a problem at once
@@ -375,53 +375,13 @@
 ##
 #########################################################
 #########################################################
-sub RadioResponseAnalysis {
+sub radio_response_analysis {
     my ($r,$problem,$problem_analysis,$students) = @_;
-    if ($ENV{'form.AnalyzeOver'} eq 'tries') {
-        &RR_tries_analysis($r,$problem,$problem_analysis,$students);
-    } elsif ($ENV{'form.AnalyzeOver'} eq 'time') {
-        &RR_static_time_analysis($r,$problem,$problem_analysis,$students);
-    } else {
+    #
+    if ($ENV{'form.AnalyzeOver'} !~ /^(tries|time)$/) {
         $r->print('Bad request');
     }
-    return;
-}
-
-sub RR_computed_tries_analysis {
-    my ($r,$problem,$problem_analysis) = @_;
-    my ($resource,$partid,$respid) = ($problem->{'resource'},
-                                      $problem->{'part'},
-                                      $problem->{'respid'});
-    $r->print('The tries answer you seek must be computed');
-    # Gather student data
-    # for each try
-    #    loop through data, classifying it by
-    #         correct foil -> selected foil
-    #    if there is concept data
-    #         make a concept correct plot
-    #    for each correct foil
-    #         make a plot of the data
-}
-
-sub RR_computed_time_analysis {
-    my ($r,$problem,$problem_analysis) = @_;
-    my ($resource,$partid,$respid) = ($problem->{'resource'},
-                                      $problem->{'part'},
-                                      $problem->{'respid'});
-    $r->print('The time answer you seek must be computed');
-    # Gather student data
-    # for time division
-    #    limit to between start time & end time
-    #    loop through data, classifying it by
-    #         correct foil -> selected foil
-    #    if there is concept data
-    #         make a concept correct plot
-    #    for each correct foil
-    #         make a plot of the data
-}
-
-sub RR_tries_analysis {
-    my ($r,$problem,$problem_analysis,$students) = @_;
+    #
     my ($resource,$partid,$respid) = ($problem->{'resource'},
                                       $problem->{'part'},
                                       $problem->{'respid'});
@@ -429,6 +389,14 @@
     my $analysis_html;
     my $foildata = $problem_analysis->{'_Foils'};
     my ($table,$foils,$concepts) = &build_foil_index($problem_analysis);
+    #
+    my $num_true = 0;
+    foreach my $foil (@$foils) {
+        if ($foildata->{$foil}->{'value'} eq 'true') {
+            $num_true++; 
+        }
+    }
+    #
     $analysis_html .= $table;
     # Gather student data
     my $response_data = &Apache::loncoursedata::get_response_data
@@ -451,12 +419,11 @@
         foreach my $foil (keys(%$foildata)) {
             if ($foildata->{$foil}->{'value'} eq 'true') {
                 $correct = $foildata->{$foil}->{'name'};
-                last;
             }
         }
     }
-    if (! defined($response_data) || 
-        ref($response_data) ne 'ARRAY' ) {
+    #
+    if (! defined($response_data) || ref($response_data) ne 'ARRAY' ) {
         $analysis_html = '<h2>'.
             &mt('There is no submission data for this resource').
             '</h2>';
@@ -465,12 +432,59 @@
     }
     #
     $analysis_html.='<table>';
-    for (my $try = 1;$try<=$ENV{'form.NumPlots'};$try++) {
+    for (my $plot_num = 1;$plot_num<=$ENV{'form.NumPlots'};$plot_num++) {
+        &Apache::lonnet::logthis('plot num = '.$plot_num);
         # classify data ->correct foil -> selected foil
-        my $attempt_restriction_function = 
-        my $foil_choice_data = 
+        my ($restriction_function,
+            $correct_foil_title,$incorrect_foil_title,
+            $pre_graph_text,$post_graph_text,
+            $no_data_text,@extra_data);
+        if ($ENV{'form.AnalyzeOver'} eq 'tries') {
+            $restriction_function = sub {($_[0]->{'tries'} == $plot_num?1:0)};
+            $correct_foil_title = 'Attempt '.$plot_num;
+            $incorrect_foil_title = 'Attempt '.$plot_num;
+            $pre_graph_text = 
+                'Attempt [_1], [_2] submissions, [_3] correct, [_4] incorrect';
+            $post_graph_text = '';
+            $no_data_text = 'No data exists for attempt [_1]';
+        } elsif ($ENV{'form.AnalyzeOver'} eq 'time') {
+            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);
+            $pre_graph_text = 
+                'Data from [_5] to [_6], [_2] submissions, [_3] correct, [_4] incorrect';
+            $extra_data[0] = &Apache::lonlocal::locallocaltime($starttime);
+            $extra_data[1] = &Apache::lonlocal::locallocaltime($endtime);
+            #
+            $post_graph_text = 
+                &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_text = 'No data for [_5] to [_6]';
+        }
+        my $foil_choice_data =
             &RR_classify_response_data($response_data,$correct,
-                                       sub {($_[0]->{'tries'} == $try?1:0)});
+                                       $restriction_function);
+        # &Apache::lonstathelpers::log_hash_ref($foil_choice_data);
         my $answers;
         if (ref($correct)) {
             my %tmp;
@@ -485,36 +499,82 @@
         my $concept_plot = '';
         if (scalar(@$concepts) > 1) {
             $concept_plot = &RR_concept_plot($concepts,$foil_choice_data,
-                                             '% choosing');
+                                             'Correct Concepts');
         }
         # % Choosing plot
         my $choice_plot = &RR_create_percent_selected_plot
-            ($foils,$foil_choice_data,'Attempt '.$try);
+            ($concepts,$foils,$foil_choice_data,$correct_foil_title);
         # for each correct foil, how did they mark it? (stacked bar graph)
-        my ($stacked_plot,$count_by_foil) = 
-            &RR_create_stacked_selection_plot($foils,$foil_choice_data,'');
+        my ($stacked_plot,$count_by_foil);
+        if ($problem_analysis->{'answercomputed'} || $num_true > 1) {
+            ($stacked_plot,$count_by_foil) =
+                &RR_create_stacked_selection_plot($foils,$foil_choice_data,
+                                                  $incorrect_foil_title);
+        }
         #
         if ($concept_plot ne '' ||
-            $choice_plot ne '' ||
+            $choice_plot  ne '' ||
             $stacked_plot ne '') {
+            my $correct = $foil_choice_data->{'_correct'};
+            if (! defined($correct) || $correct eq '') {
+                $correct = 0;
+            }
+            my $incorrect = 
+            $analysis_html.= '<tr><td colspan="4" align="center">'.
+                '<font size="+1">'.
+                &mt($pre_graph_text,
+                    $plot_num,$foil_choice_data->{'_count'},
+                    $correct,                    
+                    $foil_choice_data->{'_count'}-$correct,
+                    @extra_data).
+                    '</td></tr>'.$/;
             $analysis_html.=
                 '<tr>'.
                 '<td>'.$concept_plot.'</td>'.
                 '<td>'.$choice_plot.'</td>';
             if ($stacked_plot ne '') {
                 $analysis_html .= 
-                '<td>'.$stacked_plot.'</td>'.
-                '<td>'.&build_foil_key($foils,$count_by_foil).'</td>';
+                    '<td>'.$stacked_plot.'</td>'.
+                    '<td>'.&build_foil_key($foils,$count_by_foil).'</td>';
             } else {
                 $analysis_html .= ('<td></td>'x2);
             }
             $analysis_html.='</tr>'.$/;
+            if (defined($post_graph_text)) {
+                $analysis_html.= '<tr><td colspan="4" align="center">'.
+                    $post_graph_text.'</td></tr>'.$/;
+            }
+        } elsif ($no_data_text ne '') {
+            $analysis_html.='<tr><td colspan="4" align="center">'.
+                &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.='<br />'.$post_graph_text;
+            }
+            $analysis_html.='</td></tr>'.$/;
         }
-    }
+    } # end of loop for plots
     $analysis_html.='</table>';
     $r->print($analysis_html);
 }
 
+sub ensure_start_end_times {
+    my ($start,$end,$first,$last,$plot_num) = @_;
+    if (! defined($start) || ! defined($end)) {
+        my $sec_in_day = 86400;
+        my ($sday,$smon,$syear) = 
+            (localtime($last - $sec_in_day*($plot_num-1)))[3..5];
+        $start = &Time::Local::timelocal(0,0,0,$sday,$smon,$syear);
+        $end   = $start + $sec_in_day;
+        if ($plot_num == $ENV{'form.NumPlots'}) {
+            $start = $first;
+        }
+    }
+    return ($start,$end);
+}
 
 sub RR_concept_plot {
     my ($concepts,$foil_data,$title) = @_;
@@ -554,7 +614,6 @@
         $correct[$i] = sprintf('%0f',$correct[$i]/$total*100);
     }
     my $xlabel = 'concept';
-    $title.= ' (N='.$total.')';
     my $plot=  &Apache::loncommon::DrawBarGraph($title,
                                                 $xlabel,
                                                 'Percent Choosing',
@@ -565,9 +624,8 @@
     return $plot;
 }
 
-
 sub RR_create_percent_selected_plot {
-    my ($foils,$foil_data,$title) = @_;
+    my ($concepts,$foils,$foil_data,$title) = @_;
     #
     my %foil_selections;
     my %true;
@@ -604,34 +662,53 @@
     for (my $i=0;$i<=$#incorrect;$i++) {
         $incorrect[$i] = sprintf('%0f',$incorrect[$i]/$total*100);
     }
+    #
+    # Put a blank in the data sets between concepts, if there are concepts
+    my @labels;
+    if (defined($concepts) && scalar(@$concepts) > 1) {
+        my @new_correct;
+        my @new_incorrect;
+        my $foil_count = 0;
+        foreach my $concept (@$concepts) {
+            foreach (@{$concept->{'foils'}}) {
+                push(@new_correct,  $correct[$foil_count]);
+                push(@new_incorrect,$incorrect[$foil_count]);
+                push(@labels,++$foil_count);
+            }
+            push(@new_correct,'');
+            push(@new_incorrect,'');
+            push(@labels,'');
+        }
+        @correct = @new_correct;
+        @incorrect = @new_incorrect;
+    } else {
+        @labels = (1 .. scalar(@correct));
+    }
+    #
     my $xlabel = 'foil chosen';
-    $title.= ' (N='.$total.')';
     my $plot=  &Apache::loncommon::DrawBarGraph($title,
                                                 $xlabel,
                                                 'Percent Choosing',
                                                 100,
                                                 ['#33ff00','#ff3300'],
-                                                undef,
+                                                \@labels,
                                                 \@correct,
                                                 \@incorrect);
     return $plot;
 }
 
-
 sub RR_create_stacked_selection_plot {
     my ($foils,$foil_data,$title)=@_;
     #
-    my @correct_choice; # the green row
-    my @dataset; # array of array refs - multicolor rows.
-    my %filled;
+    my @dataset; # array of array refs - multicolor rows $datasets[row]->[col]
     my @labels;
-    my $count=-1;
-    my %column;
+    my $count;
+    my %column; # maps foil name to column in @datasets
     for (my $i=0;$i<scalar(@$foils);$i++) {
         next if (! exists($foil_data->{$foils->[$i]}));
         my $correct_foil = $foils->[$i];
         push(@labels,$i+1);
-        $column{$correct_foil}= ++$count;
+        $column{$correct_foil}= $count++;
         for (my $j=0;$j<scalar(@$foils);$j++) {
             my $value = 0;
             if ($i != $j ) {
@@ -655,7 +732,7 @@
             $dataset[$j]->[$bar] = 
                 sprintf('%2f',$dataset[$j]->[$bar]/$bar_total * 100);
         }
-        $count_per_foil{$foil}=' (N='.$bar_total.')';
+        $count_per_foil{$foil}=' ( '.$bar_total.' )';
         $grand_total += $bar_total;
     }
     if ($grand_total == 0) {
@@ -666,14 +743,12 @@
         push(@empty_row,0);
     }
     #
-    $title .= ' (N='.$grand_total.')';
     my $graph = &Apache::loncommon::DrawBarGraph
         ($title,'Correct Foil','foils chosen Incorrectly',
          100,$plotcolors,\@labels,\@empty_row,@dataset);
     return ($graph,\%count_per_foil);
 }
 
-
 # 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 RR_classify_response_data {
@@ -688,199 +763,16 @@
         }
         $subm{'submission'} =~ s/=\d+\s*$//;
         if (&$function(\%subm)) {
+            $submission_data{'_count'}++;
+            if (&submission_is_correct($subm{'award'})) { 
+                $submission_data{'_correct'}++;
+            }
             $submission_data{$subm{'correct'}}->{$subm{'submission'}}++;
         }
     }
     return \%submission_data;
 }
 
-sub RR_static_time_analysis {
-    my ($r,$problem,$problem_analysis) = @_;
-    my ($resource,$partid,$respid) = ($problem->{'resource'},
-                                      $problem->{'part'},
-                                      $problem->{'respid'});
-    $r->print('<h3>The time answer you seek is static</h3>');
-    my $analysis_html;
-    # Gather student data
-    my $response_data = &Apache::loncoursedata::get_response_data
-        (\@Apache::lonstatistics::SelectedSections,
-         $Apache::lonstatistics::enrollment_status,
-         $resource->{'symb'},$respid);
-    if (! defined($response_data) || 
-        ref($response_data) ne 'ARRAY' ) {
-        $analysis_html = '<h2>'.
-            &mt('There is no submission data for this resource').
-            '</h2>';
-        $r->print($analysis_html);
-        return;
-    }
-    # for time division
-
-    #    limit to between start time & end time
-    #    loop through data, classifying it by
-    #         correct foil -> selected foil
-    #    if there is concept data
-    #         make a concept correct plot
-    #    for each correct foil
-    #         make a plot of the data
-
-}
-
-
-=pod
-
-
-    } elsif ($ENV{'form.AnalyzeOver'} eq 'tries') {
-        $analysis_html .= &RR_tries_Analysis($r,$problem->{'resource'},
-                                             $PerformanceData,$problem_data);
-    } elsif ($ENV{'form.AnalyzeOver'} eq 'time') {
-        $analysis_html .= &RR_time_Analysis($r,$problem->{'resource'},
-                                            $PerformanceData,$problem_data);
-    } else {
-        $analysis_html .= '<h2>'.
-           &mt('The analysis you have selected is not supported at this time').
-            '</h2>';
-    }
-    $r->print($analysis_html);
-}
-
-sub RR_Excel_output   { 
-    my ($r,$PerformanceData,$problem_data) = @_;
-    return '<h1>No!</h1>';
-}
-
-sub RR_tries_Analysis { 
-    my ($r,$resource,$PerformanceData,$problem_data) = @_;
-    my $analysis_html;
-    my $mintries = 1;
-    my $maxtries = $ENV{'form.NumPlots'};
-    my ($table,$Foils,$Concepts) = &build_foil_index($problem_data);
-    if ((! defined($Concepts)) || (@$Concepts < 2)) {
-        $table = '<h3>'.
-            &mt('Not enough data for concept analysis.  '.
-                'Performing Foil Analysis').
-            '</h3>'.$table;
-    }
-    $analysis_html .= $table;
-    my @TryData = &RR_tries_data_analysis($r,$PerformanceData);
-        $analysis_html .= &RR_tries_Foil_Analysis($mintries,$maxtries,$Foils,
-                                                 \@TryData,$problem_data);
-    return $analysis_html;
-}
-
-sub RR_tries_data_analysis {
-    my ($r,$Attempt_data) = @_;
-    my @TryData;
-    foreach my $attempt (@$Attempt_data) {
-        my %Attempt = &hashify_attempt($attempt);
-        my ($answer,undef) = split('=',$Attempt{'submission'});
-        $TryData[$Attempt{'tries'}]->{$answer}++;
-    }
-    return @TryData;
-}
-
-sub RR_time_Analysis  { 
-    my ($r,$PerformanceData,$problem_data) = @_;
-    my $html;
-    return $html;
-}
-
-sub RR_tries_Foil_Analysis {
-    my ($min,$max,$Foils,$TryData,$problem_data) = @_;
-    my $html;
-    #
-    # Compute the data neccessary to make the plots
-    for (my $try=$min;$try<=$max;$try++) {
-        my @PlotData_Correct; 
-        my @PlotData_Incorrect;
-        next if ($try > scalar(@{$TryData}));
-        next if (! defined($TryData->[$try]));
-        my %DataSet = %{$TryData->[$try]};
-        my $total = 0;
-        foreach my $foilid (@$Foils) {
-            $total += $DataSet{$foilid};
-        }
-        foreach my $foilid (@$Foils) {
-            if ($total == 0) {
-                push (@PlotData_Correct,0);
-                push (@PlotData_Incorrect,0);
-            } else {
-                if ($problem_data->{'_Foils'}->{$foilid}->{'value'} eq 'true') {
-                    push (@PlotData_Correct,
-                          int(100*$DataSet{$foilid}/$total));
-                    push (@PlotData_Incorrect,0);
-                } else {
-                    push (@PlotData_Correct,0);
-                    push (@PlotData_Incorrect,
-                          int(100*$DataSet{$foilid}/$total));
-                }
-            }
-        }
-        my $title='Attempt '.$try.' (N='.$total.')';
-        my $xlabel = 'Foil Chosen';
-        $html.=  &Apache::loncommon::DrawBarGraph($title,
-                                                  $xlabel,
-                                                  'Percent Choosing',
-                                                  100,
-                                                  ['#33ff00','#ff3300'],
-                                                  undef,
-                                                  \@PlotData_Correct,
-                                                  \@PlotData_Incorrect);
-    }
-    return $html;
-}
-
-sub RR_tries_Concept_Analysis {
-    my ($min,$max,$Concepts,$ResponseData,$problem_data) = @_;
-    my $html;
-    return $html;
-}
-
-sub RR_time_Foil_Analysis {
-    my ($min,$max,$Foils,$ResponseData,$problem_data) = @_;
-    my $html;
-    return $html;
-}
-
-sub RR_time_Concept_Analysis {
-    my ($min,$max,$Concepts,$ResponseData,$problem_data) = @_;
-    my $html;
-    return $html;
-}
-
-
-sub get_Radio_problem_data {
-    my ($url) = @_;
-    my $Answ=&Apache::lonnet::ssi($url,('grade_target' => 'analyze'));
-    (my $garbage,$Answ)=split('_HASH_REF__',$Answ,2);
-    my %Answer = &Apache::lonnet::str2hash($Answ);
-    my %Partdata;
-    foreach my $part (@{$Answer{'parts'}}) {
-        while (my($key,$value) = each(%Answer)) {
-#            if (ref($value) eq 'ARRAY') {
-#                &Apache::lonnet::logthis('is ref part:'.$part.' '.$key.'='.join(',',@$value));
-#            } else {
-#                &Apache::lonnet::logthis('notref part:'.$part.' '.$key.'='.$value);
-#            }                
-            next if ($key !~ /^$part/);
-            $key =~ s/^$part\.//;
-            if ($key eq 'foils') {
-                $Partdata{$part}->{'_Foils'}=$value;
-            } elsif ($key eq 'options') {
-                $Partdata{$part}->{'_Options'}=$value;
-            } elsif ($key eq 'shown') {
-                $Partdata{$part}->{'_Shown'}=$value;
-            } elsif ($key =~ /^foil.value.(.*)$/) {
-                $Partdata{$part}->{$1}->{'value'}=$value;
-            } elsif ($key =~ /^foil.text.(.*)$/) {
-                $Partdata{$part}->{$1}->{'text'}=$value;
-            }
-        }
-    }
-    return %Partdata;
-}
-
-=cut
 
 #########################################################
 #########################################################
@@ -1847,7 +1739,7 @@
     my $time       = $row->[&Apache::loncoursedata::RD_timestamp()];
 #    my $tries      = $row->[&Apache::loncoursedata::RD_tries()];
     return undef if ($award eq 'MISSING_ANSWER');
-    if ($award =~ /(APPROX_ANS|EXACT_ANS)/) {
+    if (&submission_is_correct($award)) {
         $RowData{'_correct'} = 1;
     }
     $RowData{'_total'} = 1;
@@ -1868,6 +1760,15 @@
     return %RowData;
 }
 
+sub submission_is_correct {
+    my ($award) = @_;
+    if ($award =~ /(APPROX_ANS|EXACT_ANS)/) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
 1;
 
 __END__

--matthew1099063659--