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

matthew lon-capa-cvs@mail.lon-capa.org
Fri, 17 Oct 2003 22:05:45 -0000


This is a MIME encoded message

--matthew1066428345
Content-Type: text/plain

matthew		Fri Oct 17 18:05:45 2003 EDT

  Modified files:              
    /loncom/interface/statistics	lonproblemanalysis.pm 
  Log:
  Many changes, most to internal code structure.  Hopefully future changes
  will not require such monsterous rewrites.
  Foils analysis now shows two graphs, one for the correct choice on the
  foils and the other for the incorrect submissions.
  Time analysis no longer has editable plot titles.
  Added a few helper functions get_time_from_row, get_tries_from_row, and
  Process_Row.
  
  
--matthew1066428345
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20031017180545.txt"

Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.41 loncom/interface/statistics/lonproblemanalysis.pm:1.42
--- loncom/interface/statistics/lonproblemanalysis.pm:1.41	Thu Oct 16 11:24:49 2003
+++ loncom/interface/statistics/lonproblemanalysis.pm	Fri Oct 17 18:05:45 2003
@@ -1,7 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-
-# $Id: lonproblemanalysis.pm,v 1.41 2003/10/16 15:24:49 matthew Exp $
+# $Id: lonproblemanalysis.pm,v 1.42 2003/10/17 22:05:45 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -36,6 +35,7 @@
 use Apache::lonstatistics;
 use Apache::lonlocal;
 use HTML::Entities();
+use Time::Local();
 
 my $plotcolors = ['#33ff00', 
                   '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
@@ -141,7 +141,6 @@
     }
 }
 
-
 #########################################################
 #########################################################
 ##
@@ -275,6 +274,7 @@
               '<td>'.$option.'</td>'.
               "</tr>\n");
     }
+    shift(@Rows); # Throw away 'correct option chosen' color
     $table .= join('',reverse(@Rows));
     $table .= "</table>\n";
 }
@@ -300,67 +300,133 @@
     }
     my %ResponseData = &analyze_option_data_by_tries($PerformanceData,
                                                      $mintries,$maxtries);
+    my $analysis = '';
+    if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
+        $analysis = &Tries_Foil_Analysis($mintries,$maxtries,$Foils,
+                                         \%ResponseData,$ORdata);
+    } else {
+        $analysis = &Tries_Concept_Analysis($mintries,$maxtries,
+                                            $Concepts,\%ResponseData,$ORdata);
+    }
+    $table .= $analysis;
+    return $table;
+}
+
+sub Tries_Foil_Analysis {
+    my ($mintries,$maxtries,$Foils,$respdat,$ORdata) = @_;
+    my %ResponseData = %$respdat;
     #
     # Compute the data neccessary to make the plots
-    my @PlotData;   # Array which holds the data for each plot
-                    # @{$PlotData[$try]->{'datasetname'}} holds the data for
-                    # try $try with respect to 'datasetname'.  The array is
-                    # filled either with per-foil or per-concept data.
-    my ($extrakey,$xlabel,$ylabel);
-    if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
-        $extrakey = &build_option_index($ORdata);
-        $xlabel = 'Foil Number';
-        $ylabel = 'Percent Choosing Option';
-        foreach my $foilid (@$Foils) {
-            for (my $i=$mintries;$i<=$maxtries;$i++) {
-                foreach my $option ('_correct',@{$ORdata->{'Options'}}) {
-                    push(@{$PlotData[$i]->{'_total'}},
-                         $ResponseData{$foilid}->[$i]->{'_total'});
-                    if ($ResponseData{$foilid}->[$i]->{'_total'} == 0) {
-                        push (@{$PlotData[$i]->{$option}},0);
+    my @PlotData; 
+    foreach my $foilid (@$Foils) {
+        for (my $i=$mintries;$i<=$maxtries;$i++) {
+            if ($ResponseData{$foilid}->[$i]->{'_total'} == 0) {
+                push(@{$PlotData[$i]->{'_correct'}},0);
+            } else {
+                push(@{$PlotData[$i]->{'_correct'}},
+                     100*$ResponseData{$foilid}->[$i]->{'_correct'}/
+                     $ResponseData{$foilid}->[$i]->{'_total'});
+            }
+            foreach my $option (@{$ORdata->{'Options'}}) {
+                push(@{$PlotData[$i]->{'_total'}},
+                     $ResponseData{$foilid}->[$i]->{'_total'});
+                if ($ResponseData{$foilid}->[$i]->{'_total'} == 0) {
+                    push (@{$PlotData[$i]->{$option}},0);
+                } else {
+                    if ($ResponseData{$foilid}->[$i]->{'_total'} ==
+                        $ResponseData{$foilid}->[$i]->{'_correct'}) {
+                        push(@{$PlotData[$i]->{$option}},0);
                     } else {
                         push (@{$PlotData[$i]->{$option}},
                               100 * $ResponseData{$foilid}->[$i]->{$option} / 
-                                    $ResponseData{$foilid}->[$i]->{'_total'});
+                              ($ResponseData{$foilid}->[$i]->{'_total'} - 
+                               $ResponseData{$foilid}->[$i]->{'_correct'}));
                     }
                 }
             }
         }
-    } else {
-        # 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.
-        $extrakey = '';
-        $xlabel = 'Concept Number';
-        $ylabel = 'Percent Correct';
-        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'});
+    }
+    # 
+    # Build a table for the plots
+    my $analysis_html = "<table>\n";
+    my $foilkey = &build_option_index($ORdata);
+    for (my $i=$mintries;$i<=$maxtries;$i++) {
+        my $count = $ResponseData{'_total'}->[$i];
+        if ($count == 0) {
+            $count = 'no submissions';
+        } elsif ($count == 1) {
+            $count = '1 submission';
+        } else {
+            $count = $count.' submissions';
+        }
+        my $title = 'Attempt '.$i.', '.$count;
+        my @Datasets;
+        foreach my $option ('_correct',@{$ORdata->{'Options'}}) {
+            next if (! exists($PlotData[$i]->{$option}));
+            push(@Datasets,$PlotData[$i]->{$option});
+        }
+        my $correctgraph = &Apache::loncommon::DrawGraph
+            ($title,'Foil Number','Percent Correct',
+             100,$plotcolors,$Datasets[0]);
+        $analysis_html.= '<tr><td>'.$correctgraph.'</td>';
+        ##
+        ##
+        for (my $i=0; $i< scalar(@{$Datasets[0]});$i++) {
+            $Datasets[0]->[$i]=0;
+        }
+        $count = $ResponseData{'_total'}->[$i]-$ResponseData{'_correct'}->[$i];
+        if ($count == 0) {
+            $count = 'no submissions';
+        } elsif ($count == 1) {
+            $count = '1 submission';
+        } else {
+            $count = $count.' submissions';
+        }
+        $title = 'Attempt '.$i.', '.$count;
+        my $incorrectgraph = &Apache::loncommon::DrawGraph
+            ($title,'Foil Number','% Option Chosen Incorrectly',
+             100,$plotcolors,@Datasets);
+        $analysis_html.= '<td>'.$incorrectgraph.'</td>';
+        $analysis_html.= '<td>'.$foilkey."<td></tr>\n";
+    }
+    $analysis_html .= "</table>\n";
+    return $analysis_html;
+}
+
+sub Tries_Concept_Analysis {
+    my ($mintries,$maxtries,$Concepts,$respdat,$ORdata) = @_;
+    my %ResponseData = %$respdat;
+    my $analysis_html = "<table>\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'});
                 }
-            }
         }
-    } # End of work to fill @PlotData
-    # 
+    }
     # Build a table for the plots
-    $table .= "<table>\n";
-    my @Plots;
     for (my $i=$mintries;$i<=$maxtries;$i++) {
         my $minstu = $PlotData[$i]->{'_total'}->[0];
         my $maxstu = $PlotData[$i]->{'_total'}->[0];
@@ -375,31 +441,22 @@
         $maxstu = 0 if (! defined($maxstu));
         $minstu = 0 if (! defined($minstu));
         my $title;
-        if ($maxstu == $minstu) {
-            $title = 'Attempt '.$i.', '.$maxstu.' students';
+        my $count = $ResponseData{'_total'}->[$i];
+        if ($count == 0) {
+            $count = 'no submissions';
+        } elsif ($count == 1) {
+            $count = '1 submission';
         } else {
-            $title = 'Attempt '.$i.', '.$minstu.'-'.$maxstu.' students';
-        }
-        my @Datasets;
-        foreach my $option ('_correct',@{$ORdata->{'Options'}}) {
-            next if (! exists($PlotData[$i]->{$option}));
-            push(@Datasets,$PlotData[$i]->{$option});
+            $count = $count.' submissions';
         }
-        my $graphlink = &Apache::loncommon::DrawGraph($title,
-                                                      $xlabel,
-                                                      $ylabel,
-                                                      100,
-                                                      $plotcolors,
-                                                      @Datasets);
-        push(@Plots,$graphlink);
+        $title = 'Attempt '.$i.', '.$count;
+        my $graphlink = &Apache::loncommon::DrawGraph
+            ($title,'Concept Number','Percent Correct',
+             100,$plotcolors,$PlotData[$i]->{'_correct'});
+        $analysis_html.= '<tr><td>'.$graphlink."</td></tr>\n";
     }
-    #
-    # Should this be something the user can set?  Too many dialogs!
-    while (my $plotlink = shift(@Plots)) {
-        $table .= '<tr><td>'.$plotlink.'</td><td>'.$extrakey."</td></tr>\n";
-    }
-    $table .= "</table>\n";
-    return ($table);
+    $analysis_html .= "</table>\n";
+    return $analysis_html;
 }
 
 sub analyze_option_data_by_tries {
@@ -409,23 +466,15 @@
     $maxtries = $mintries if (! defined($maxtries) || $maxtries < $mintries);
     foreach my $row (@$PerformanceData) {
         next if (! defined($row));
-        my ($grading,$submission,$time,$tries) = @$row;
-        next if ($grading eq 'MISSING_ANSWER');
-        my @Foilgrades = split('&',$grading);
-        my @Foilsubs   = split('&',$submission);
-        for (my $numtries = 1; $numtries <= $maxtries; $numtries++) {
-            if ($tries == $numtries) {
-                for (my $i=0;$i<=$#Foilgrades;$i++) {
-                    my ($foilid,$correct)  = split('=',$Foilgrades[$i]);
-                    my (undef,$submission) = split('=',$Foilsubs[$i]);
-                    $submission = &Apache::lonnet::unescape($submission);
-                    if ($correct) {
-                        $Trydata{$foilid}->[$numtries]->{'_correct'}++;
-                    } else {
-                        $Trydata{$foilid}->[$numtries]->{$submission}++;
-                    }                        
-                    $Trydata{$foilid}->[$numtries]->{'_total'}++;
-                }
+        my $tries = &get_tries_from_row($row);
+        my %Row   = &Process_Row($row);
+        while (my ($foilid,$href) = each(%Row)) {
+            if (! ref($href)) { 
+                $Trydata{$foilid}->[$tries] += $href;
+                next;
+            }
+            while (my ($option,$value) = each(%$href)) {
+                $Trydata{$foilid}->[$tries]->{$option}+=$value;
             }
         }
     }
@@ -441,141 +490,242 @@
 #########################################################
 sub time_analysis {
     my ($PerformanceData,$ORdata) = @_;
-    my $num_plots = $ENV{'form.NumPlots'};
     my ($table,$Foils,$Concepts) = &build_foil_index($ORdata);
+    if ((@$Concepts < 2) && ($ENV{'form.AnalyzeAs'} ne 'Foils')) {
+        $table = '<h3>'.
+            &mt('Not enough data for concept analysis.  '.
+                'Performing Foil Analysis').
+            '</h3>'.$table;
+        $ENV{'form.AnalyzeAs'} = 'Foils';
+    }
+    my $num_plots = $ENV{'form.NumPlots'};
     my $num_data = scalar(@$PerformanceData)-1;
     my $percent = sprintf('%2f',100/$num_plots);
-    my $extratable = '';
-    if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
-        $extratable = &build_option_index($ORdata);
-    }
+    #
     $table .= "<table>\n";
     for (my $i=0;$i<$num_plots;$i++) {
+        ##
         my $starttime = &Apache::lonhtmlcommon::get_date_from_form
             ('startdate_'.$i);
         my $endtime = &Apache::lonhtmlcommon::get_date_from_form
             ('enddate_'.$i);
-        my ($begin_index,$end_index,$plottitle,$plothtml,$data);
         if (! defined($starttime) || ! defined($endtime)) {
-            $begin_index = $i*int($num_data/$num_plots);
-            $end_index = ($i+1)*int($num_data/$num_plots);
-            my $lownum  = sprintf('%2.1f',$i*$percent);
-            $lownum =~ s/(\.0)$//;
-            my $highnum = sprintf('%2.1f',($i+1)*$percent);
-            $highnum =~ s/(\.0)$//;
-            $plottitle = $lownum.'% to '.$highnum.'% of submissions';
-        } else {
-            my $j;
-            while (++$j < scalar(@$PerformanceData)) {
-                last if ($PerformanceData->[$j]->[2] > $starttime);
-            }
-            $begin_index = $j;
-            while (++$j < scalar(@$PerformanceData)) {
-                last if ($PerformanceData->[$j]->[2] > $endtime);
-            }
-            $end_index = $j;
-            $plottitle = $ENV{'form.plottitle_'.$i};
-        }
-        ($plothtml,$starttime,$endtime,$data) = 
-            &analyze_option_data_by_time($PerformanceData,
-                                         $begin_index,$end_index,
-                                         $plottitle,$Foils,
-                                         $Concepts,$ORdata);
+            my $sec_in_day = 86400;
+            my $last_sub_time = &get_time_from_row($PerformanceData->[-1]);
+            my ($sday,$smon,$syear);
+            (undef,undef,undef,$sday,$smon,$syear) = 
+                localtime($last_sub_time - $sec_in_day*$i);
+            $starttime = &Time::Local::timelocal(0,0,0,$sday,$smon,$syear);
+            $endtime = $starttime + $sec_in_day;
+            if ($i == ($num_plots -1 )) {
+                $starttime = &get_time_from_row($PerformanceData->[0]);
+            }
+        }
         my $startdateform = &Apache::lonhtmlcommon::date_setter
             ('Statistics','startdate_'.$i,$starttime);
         my $enddateform = &Apache::lonhtmlcommon::date_setter
             ('Statistics','enddate_'.$i,$endtime);
-        $table.="<tr><td>".$plothtml.'</td><td align="left" valign="top">'.
-            "<b>Start Time</b>: &nbsp;".$startdateform."<br />".
-            "<b>End Time</b>&nbsp;&nbsp;: "."&nbsp;".$enddateform."<br />".
-            '<b>Plot Title</b>&nbsp;&nbsp;:'.("&nbsp;"x3).
-            '<input type="text" size="30" name="plottitle_'.$i.'" value="'.
-                  &HTML::Entities::encode($plottitle).'" /><br />'.$extratable.
-            "</td></tr>\n";
+        #
+        my $begin_index;
+        my $end_index;
+        my $j;
+        while (++$j < scalar(@$PerformanceData)) {
+            last if (&get_time_from_row($PerformanceData->[$j]) > $starttime);
+        }
+        $begin_index = $j;
+        while (++$j < scalar(@$PerformanceData)) {
+            last if (&get_time_from_row($PerformanceData->[$j]) > $endtime);
+        }
+        $end_index = $j;
+        ##
+        my $interval = {
+            begin_index => $begin_index,
+            end_index   => $end_index,
+            startdateform => $startdateform,
+            enddateform   => $enddateform,
+        };
+        if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
+            $table .= &Foil_Time_Analysis($PerformanceData,$ORdata,$Foils,
+                                          $interval);
+        } else {
+            $table .= &Concept_Time_Analysis($PerformanceData,$ORdata,
+                                             $Concepts,$interval);
+        }
     }
-    $table .="</table>\n";
+    #
     return $table;
 }
 
-sub analyze_option_data_by_time {
-    my ($PerformanceData,$begin_index,
-        $end_index,$description,$Foils,$Concepts,$ORdata) = @_;
+sub Foil_Time_Analysis {
+    my ($PerformanceData,$ORdata,$Foils,$interval) = @_;
+    my $analysis_html;
+    my $foilkey = &build_option_index($ORdata);
+    my ($begin_index,$end_index) = ($interval->{'begin_index'},
+                                    $interval->{'end_index'});
     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];
+    for (my $j=$begin_index;$j<=$end_index;$j++) {
+        my $row = $PerformanceData->[$j];
         next if (! defined($row));
-        my ($grading,$submission,$time,$tries) = @$row;
-        next if ($grading eq 'MISSING_ANSWER');
-        my @Foilgrades = split('&',$grading);
-        my @Foilsubs   = split('&',$submission);
-        for (my $j=0;$j<=$#Foilgrades;$j++) {
-            my ($foilid,$correct)  = split('=',$Foilgrades[$j]);
-            my (undef,$submission) = split('=',$Foilsubs[$j]);
-            if ($correct) {
-                $TimeData{$foilid}->{'_correct'}++;
-            } else {
-                $submission = &HTML::Entities::decode($submission);
-                $submission =~ s/\%20/ /g;
-                $TimeData{$foilid}->{$submission}++;
+        my %Row = &Process_Row($row);
+        while (my ($foilid,$href) = each(%Row)) {
+            if (! ref($href)) {
+                $TimeData{$foilid} += $href;
+                next;
+            }
+            while (my ($option,$value) = each(%$href)) {
+                $TimeData{$foilid}->{$option}+=$value;
             }
-            $TimeData{$foilid}->{'_total'}++;
         }
     }
-    #
-    # Compute the total and percent correct
     my @Plotdata;
-    my ($xlabel,$ylabel);
-    if ($ENV{'form.AnalyzeAs'} eq 'Foils') {
-        $xlabel = 'Foil Number';
-        $ylabel = 'Option Chosen';
-        foreach my $foil (@$Foils) {
-            my $total = $TimeData{$foil}->{'_total'};
-            my $optionidx = 0;
-            foreach my $option ('_correct',@{$ORdata->{'Options'}}) {
-                if ($total > 0) {
-                    push(@{$Plotdata[$optionidx]},
-                         100 * $TimeData{$foil}->{$option} / $total);
-                } else {
-                    push(@{$Plotdata[$optionidx]},0);
-                }
-            } continue {
-                $optionidx++;
+    foreach my $foil (@$Foils) {
+        my $total = $TimeData{$foil}->{'_total'};
+        if ($total == 0) {
+            push(@{$Plotdata[0]},0);
+        } else {
+            push(@{$Plotdata[0]},
+                 100 * $TimeData{$foil}->{'_correct'} / $total);
+        }
+        my $total_incorrect = $total - $TimeData{$foil}->{'_correct'};
+        my $optionidx = 1;
+        foreach my $option (@{$ORdata->{'Options'}}) {
+            if ($total_incorrect == 0) {
+                push(@{$Plotdata[$optionidx]},0);
+            } else {
+                push(@{$Plotdata[$optionidx]},
+                     100 * $TimeData{$foil}->{$option} / $total_incorrect);
             }
+        } continue {
+            $optionidx++;
         }
+    }
+    #
+    # Create the plot
+    my $count = $end_index-$begin_index;
+    my $title;
+    if ($count == 0) {
+        $title = 'no submissions';
+    } elsif ($count == 1) {
+        $title = 'one submission';
     } else {
-        $xlabel = 'Concept Number';
-        $ylabel = 'Percent Correct';
-        foreach my $concept (@$Concepts) {
-            my $correct;
-            my $total;
-            foreach my $foil (@{$concept->{'foils'}}) {
-                $correct+=$TimeData{$foil}->{'_correct'};
-                $total  +=$TimeData{$foil}->{'_total'};
+        $title = $count.' submissions';
+    }
+    my $correctplot = &Apache::loncommon::DrawGraph($title,
+                                                    'Foil Number',
+                                                    'Percent Correct',
+                                                    100,
+                                                    $plotcolors,
+                                                    $Plotdata[0]);
+    for (my $j=0; $j< scalar(@{$Plotdata[0]});$j++) {
+        $Plotdata[0]->[$j]=0;
+    }
+    $count = $end_index-$begin_index-$TimeData{'_correct'};
+    if ($count == 0) {
+        $title = 'no submissions';
+    } elsif ($count == 1) {
+        $title = 'one submission';
+    } else {
+        $title = $count.' submissions';
+    }
+    my $incorrectplot = &Apache::loncommon::DrawGraph($title,
+                                                 'Foil Number',
+                                                 'Incorrect Option Choice',
+                                                 100,
+                                                 $plotcolors,
+                                                 @Plotdata);        
+    $analysis_html.='<tr>'.
+        '<td>'.$correctplot.'</td>'.
+        '<td>'.$incorrectplot.'</td>'.
+        '<td align="left" valign="top">'.$foilkey.'</td>'."</tr>\n";
+    $analysis_html.= '<tr>'.'<td colspan="3">'.
+        '<b>Start Time</b>:'.
+        ' &nbsp;'.$interval->{'startdateform'}.'<br />'.
+        '<b>End Time</b>&nbsp;&nbsp;: '.
+        '&nbsp;'.$interval->{'enddateform'}.'<br />'.
+#        '<b>Plot Title</b>&nbsp;&nbsp;:'.
+#        ("&nbsp;"x3).$interval->{'titleform'}.
+        '</td>'.
+        "</tr>\n";
+    return $analysis_html;
+}
+
+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)) {
+            if (! ref($href)) {
+                $TimeData{$foilid} += $href;
+                next;
             }
-            if ($total > 0) {
-                push(@{$Plotdata[0]},100 * $correct / $total);
-            } else {
-                push(@{$Plotdata[0]},0);
+            while (my ($option,$value) = each(%$href)) {
+                $TimeData{$foilid}->{$option}+=$value;
             }
         }
     }
     #
-    # Create the plot
-    my $graphlink = &Apache::loncommon::DrawGraph
-        ($description,#'Time Interval Analysis',
-         $xlabel,
-         $ylabel,
-         100,
-         $plotcolors,
-         @Plotdata);
+    # 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'};
+        }
+        if ($total == 0) {
+            push(@Plotdata,0);
+        } else {
+            push(@Plotdata,100 * $correct / $total);
+        }
+    }
     #
-    return ($graphlink,$starttime,$endtime,\%TimeData);
+    # 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.='<tr>'.
+        '<td>'.$correctplot.'</td>'.
+        '<td align="left" valign="top">'.
+        '<b>Start Time</b>: &nbsp;'.$interval->{'startdateform'}.'<br />'.
+        '<b>End Time</b>&nbsp;&nbsp;: '.
+           '&nbsp;'.$interval->{'enddateform'}.'<br />'.
+#        '<b>Plot Title</b>&nbsp;&nbsp;:'.("&nbsp;"x3).
+#            $interval->{'titleform'}.
+        '</td>'.
+        "</tr>\n";
+    return $analysis_html;
+}
+
+#########################################################
+#########################################################
+##
+##             Excel output 
+##
+#########################################################
+#########################################################
+sub prepare_excel_sheet {
+    my ($PerformanceData,$ORdata) = @_;
+    my (undef,$Foils,$Concepts) = &build_foil_index($ORdata);
+}
+
+sub process_data_for_excel_sheet {
+    my ($PerformanceData,$Foils,$Concepts,$ORdata)=@_;
 }
 
 #########################################################
@@ -677,7 +827,7 @@
     ##
     $Str .= '</tr>'."\n";
     $Str .= '</table>'."\n";
-    return ($Str);
+    return $Str;
 }
 
 sub OptionResponseProblemSelector {
@@ -747,6 +897,48 @@
         }
     }
     return undef;
+}
+
+sub get_time_from_row {
+    my ($row) = @_;
+    if (ref($row)) {
+        return $row->[3];
+    } 
+    return undef;
+}
+
+sub get_tries_from_row {
+    my ($row) = @_;
+    if (ref($row)) {
+        return $row->[4];
+    }
+    return undef;
+}
+
+sub Process_Row {
+    my ($row) = @_;
+    my %RowData;
+    my ($award,$grading,$submission,$time,$tries) = @$row;
+    next if ($award eq 'MISSING_ANSWER');
+    if ($award =~ /(APPROX_ANS|EXACT_ANS)/) {
+        $RowData{'_correct'} = 1;
+    }
+    $RowData{'_total'} = 1;
+    my @Foilgrades = split('&',$grading);
+    my @Foilsubs   = split('&',$submission);
+    for (my $j=0;$j<=$#Foilgrades;$j++) {
+        my ($foilid,$correct)  = split('=',$Foilgrades[$j]);
+        my (undef,$submission) = split('=',$Foilsubs[$j]);
+        if ($correct) {
+            $RowData{$foilid}->{'_correct'}++;
+        } else {
+            $submission = &Apache::lonnet::unescape($submission);
+            $submission =~ s/\%20/ /g;
+            $RowData{$foilid}->{$submission}++;
+        }
+        $RowData{$foilid}->{'_total'}++;
+    }
+    return %RowData;
 }
 
 ##

--matthew1066428345--