--- loncom/interface/statistics/lonproblemanalysis.pm 2003/09/29 21:09:27 1.23
+++ loncom/interface/statistics/lonproblemanalysis.pm 2006/12/21 19:52:28 1.129
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonproblemanalysis.pm,v 1.23 2003/09/29 21:09:27 matthew Exp $
+# $Id: lonproblemanalysis.pm,v 1.129 2006/12/21 19:52:28 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -24,202 +24,1976 @@
#
# http://www.lon-capa.org/
#
-# (Navigate problems for statistical reports
-# YEAR=2002
-# 5/12,7/26,9/7,11/22 Behrouz Minaei
-#
-###
-
package Apache::lonproblemanalysis;
use strict;
-use Apache::lonnet();
+use Apache::lonnet;
+use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::loncoursedata();
use Apache::lonstatistics;
use Apache::lonlocal;
+use Apache::lonstathelpers();
+use Apache::lonstudentsubmissions();
+use HTML::Entities();
+use Time::Local();
+use capa;
+use lib '/home/httpd/lib/perl/';
+use LONCAPA;
+
+
+my $plotcolors = ['#33ff00',
+ '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
+ '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
+ ];
+
+my @SubmitButtons = ({ name => 'PrevProblemAnalysis',
+ text => 'Previous Problem' },
+ { name => 'ProblemAnalysis',
+ text => 'Analyze Problem Again' },
+ { name => 'NextProblemAnalysis',
+ text => 'Next Problem' },
+ { name => 'break'},
+ { name => 'SelectAnother',
+ text => 'Choose a different Problem' });
sub BuildProblemAnalysisPage {
my ($r,$c)=@_;
- $r->print(&mt('
Option Response Problem Analysis
'));
- if (exists($ENV{'form.problemchoice'})) {
- # This is me getting around my own cleverness:
- &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
- undef);
- #
- my ($symb,$id) = &get_problem_symb(
- &Apache::lonnet::unescape($ENV{'form.problemchoice'})
- );
+ #
+ my %Saveable_Parameters = ('Status' => 'scalar',
+ 'Section' => 'array',
+ 'Groups' => 'array',
+ 'NumPlots' => 'scalar',
+ 'AnalyzeOver' => 'scalar',
+ );
+ &Apache::loncommon::store_course_settings('problem_analysis',
+ \%Saveable_Parameters);
+ &Apache::loncommon::restore_course_settings('problem_analysis',
+ \%Saveable_Parameters);
+ #
+ &Apache::lonstatistics::PrepareClasslist();
+ #
+ $r->print(&CreateInterface());
+ #
+ my @Students = @Apache::lonstatistics::Students;
+ #
+ if (@Students < 1 && exists($env{'form.firstrun'})) {
+ $r->print('
There are no students in the sections/groups selected
');
+ }
+ #
+ my @CacheButtonHTML =
+ &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status');
+ $r->rflush();
+ #
+ my $problem_types = '(option|radiobutton|numerical)';
+ if (exists($env{'form.problemchoice'}) &&
+ ! exists($env{'form.SelectAnother'})) {
+ foreach my $button (@SubmitButtons) {
+ if ($button->{'name'} eq 'break') {
+ $r->print(" \n");
+ } else {
+ $r->print('{'text'}).'" />');
+ $r->print(' 'x5);
+ }
+ }
+ foreach my $html (@CacheButtonHTML) {
+ $r->print($html.(' 'x5));
+ }
+ #
+
+ # This is commented out pending actual implementation of
+ # CSV and Excel output.
+ #$r->print(&Apache::lonstathelpers::submission_report_form
+ # ('problem_analysis'));
+ #
$r->print('');
- my $resource = &get_resource_from_symb($symb);
- if (defined($resource)) {
- $r->print('
'.
- # Oh this is dumb! Need to rewrite relative links
- # otherwise images (for example) will not show.
- &Apache::lonnet::ssi_body($resource->{'src'}).
- '
');
+ $r->rflush();
+ #
+ # Determine which problem we are to analyze
+ my $current_problem = &Apache::lonstathelpers::get_target_from_id
+ ($env{'form.problemchoice'});
+ #
+ my ($navmap,$prev,$curr,$next) =
+ &Apache::lonstathelpers::get_prev_curr_next($current_problem,
+ $problem_types,
+ 'response',
+ );
+ if (exists($env{'form.PrevProblemAnalysis'}) && defined($prev)) {
+ $current_problem = $prev;
+ } elsif (exists($env{'form.NextProblemAnalysis'}) && defined($next)) {
+ $current_problem = $next;
} else {
+ $current_problem = $curr;
+ }
+ #
+ # Store the current problem choice and send it out in the form
+ $env{'form.problemchoice'} =
+ &Apache::lonstathelpers::make_target_id($current_problem);
+ $r->print('');
+ #
+ if (! defined($current_problem->{'resource'})) {
$r->print('resource is undefined');
+ } else {
+ my $resource = $current_problem->{'resource'};
+ $r->print('
'.
+ &mt('There is no submission data for this resource').
+ '
');
return;
}
- # Okay, they asked for data, so make sure we get the latest data.
- &Apache::lonnet::logthis('got here for some reason');
-# &Apache::lonstatistics::Gather_Full_Student_Data($r);
- $r->print(&OptionResponseProblemSelector());
+ my $analysis_html = '
';
+ for (my $plot_num = 1;$plot_num<=$env{'form.NumPlots'};$plot_num++) {
+ my $restriction_function;
+ 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)).
+ ' '.
+ &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,$answers) =
+ &numerical_determine_answers($r,$resource,$partid,
+ $respid,$students);
+ if ($c->aborted()) { return; };
+ #
+ my ($responses,$stats) =
+ &numerical_classify_responses($response_data,$correct,
+ $restriction_function);
+ if ($stats->{'submission_count'} == 0) {
+ $analysis_html.=
+ '
'.
+ &mt('The analysis you have selected is '.
+ 'not supported at this time').
+ '
');
+ }
+ }
+}
+
+#########################################################
+#
+# Option Response: tries Analysis
+#
+#########################################################
+sub OR_tries_analysis {
+ my ($r,$PerformanceData,$ORdata) = @_;
+ my $mintries = 1;
+ my $maxtries = $env{'form.NumPlots'};
+ my ($table,$Foils,$Concepts) = &build_foil_index($ORdata);
+ if (! defined($Concepts)) {
+ $Concepts = [];
+ }
+ my %response_data = &OR_analyze_by_tries($r,$PerformanceData,
+ $mintries,$maxtries);
+ my $analysis = '';
+ #
+ # Compute the data necessary to make the plots
+ my @foil_plot;
+ my @concept_data;
+ for (my $j=0;$j<=scalar(@$Concepts);$j++) {
+ my $concept = $Concepts->[$j];
+ foreach my $foilid (@{$concept->{'foils'}}) {
+ for (my $try=$mintries;$try<=$maxtries;$try++) {
+ # concept analysis data
+ $concept_data[$j]->[$try]->{'_correct'} +=
+ $response_data{$foilid}->[$try]->{'_correct'};
+ $concept_data[$j]->[$try]->{'_total'} +=
+ $response_data{$foilid}->[$try]->{'_total'};
+ #
+ # foil analysis data
+ if ($response_data{$foilid}->[$try]->{'_total'} == 0) {
+ push(@{$foil_plot[$try]->{'_correct'}},0);
+ } else {
+ push(@{$foil_plot[$try]->{'_correct'}},
+ 100*$response_data{$foilid}->[$try]->{'_correct'}/
+ $response_data{$foilid}->[$try]->{'_total'});
+ }
+ foreach my $option (@{$ORdata->{'_Options'}}) {
+ push(@{$foil_plot[$try]->{'_total'}},
+ $response_data{$foilid}->[$try]->{'_total'});
+ if ($response_data{$foilid}->[$try]->{'_total'} == 0) {
+ push (@{$foil_plot[$try]->{$option}},0);
+ } else {
+ if ($response_data{$foilid}->[$try]->{'_total'} ==
+ $response_data{$foilid}->[$try]->{'_correct'}) {
+ push(@{$foil_plot[$try]->{$option}},0);
+ } else {
+ push (@{$foil_plot[$try]->{$option}},
+ 100 *
+ $response_data{$foilid}->[$try]->{$option} /
+ ($response_data{$foilid}->[$try]->{'_total'}
+ -
+ $response_data{$foilid}->[$try]->{'_correct'}
+ ));
}
- $seq_str .= "
\n";
}
+ } # End of foreach my $option
+ }
+ } # End of foreach my $foilid
+ } # End of concept loops
+ #
+ # Build a table for the plots
+ my $analysis_html = "
\n";
+ my $optionkey = &build_option_index($ORdata);
+ my $num_concepts = 1;
+ if (defined($Concepts)) { $num_concepts = scalar(@$Concepts); }
+ #
+ for (my $try=$mintries;$try<=$maxtries;$try++) {
+ if (! defined($response_data{'_total'}->[$try]) ||
+ $response_data{'_total'}->[$try] == 0) {
+ if ($try > 1) {
+ $analysis_html.= '
'.
+ &mt('None of the selected students attempted the problem more than [_1] times.',$try-1).
+ '
';
+ } else {
+ $analysis_html.= '
'.
+ &mt('None of the selected students have attempted the problem').'
';
+ }
+ last;
+ }
+ my $concept_graph='';
+ if ($num_concepts > 1) {
+ #
+ # Create concept plot
+ my @concept_plot_data;
+ for (my $j=0;$j<=$#concept_data;$j++) {
+ my $total = $concept_data[$j]->[$try]->{'_total'};
+ if ($total == 0) {
+ $concept_plot_data[$j] = 0;
+ } else {
+ $concept_plot_data[$j] = 100 *
+ sprintf('%0.3f',
+ $concept_data[$j]->[$try]->{'_correct'} /
+ $total);
}
}
+ #
+ $concept_graph = &Apache::loncommon::DrawBarGraph
+ ('Correct Concepts','Concept Number','Percent Correct',
+ 100,$plotcolors,undef,\@concept_plot_data,{xskip=>1});
+ }
+ #
+ # 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,'');
}
- if ($seq_str ne '') {
- $Str .= '
 
'.$seq->{'title'}.'
'.
- "
\n".$seq_str;
+ #
+ 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.=
+ '