'."\n";
+ $Str .= '';
+ $Str .= ' 'x5;
+ $Str .= 'Plot '.&plot_dropdown().(' 'x10);
+ $Str .= '';
+ $Str .= ' 'x5;
+ $Str .= '';
+ $Str .= ' 'x5;
+ $Str .= '';
+ $Str .= ' 'x5;
return $Str;
}
-#######################################################
-#######################################################
+###############################################
+###############################################
-=pod
+=pod
-=item &CreateAndParseOutputSelector()
+=item &BuildProblemStatisticsPage()
-=cut
+Main interface to problem statistics.
-#######################################################
-#######################################################
-my $output_mode;
-my $show;
-
-my @OutputOptions =
- (
- { name => 'problem statistics grouped by sequence',
- value => 'HTML problem statistics grouped',
- description => 'Output statistics for the problem parts.',
- mode => 'html',
- show => 'grouped',
- },
- { name => 'problem statistics ungrouped',
- value => 'HTML problem statistics ungrouped',
- description => 'Output statistics for the problem parts.',
- mode => 'html',
- show => 'ungrouped',
- },
- { name => 'problem statistics, Excel',
- value => 'Excel problem statistics',
- description => 'Output statistics for the problem parts '.
- 'in an Excel workbook',
- mode => 'excel',
- show => 'all',
- },
- { name => 'Degree of Difficulty Plot',
- value => 'plot deg diff',
- description => 'Generate a plot of the degree of difficulty of each '.
- 'problem part.',
- mode => 'plot',
- show => 'deg of diff',
- },
- { name => 'Percent Wrong Plot',
- value => 'plot per wrong',
- description => 'Generate a plot showing the percent of students who '.
- 'were unable to complete each problem part',
- mode => 'plot',
- show => 'per wrong',
- },
- );
+=cut
-sub OutputDescriptions {
- my $Str = '';
- $Str .= "
Output Modes
\n";
- $Str .= "
\n";
- foreach my $outputmode (@OutputOptions) {
- $Str .="
".$outputmode->{'name'}."
\n";
- $Str .="
".$outputmode->{'description'}."
\n";
+###############################################
+###############################################
+sub BuildProblemStatisticsPage {
+ my ($r,$c)=@_;
+ #
+ my %Saveable_Parameters = ('Status' => 'scalar',
+ 'statsoutputmode' => 'scalar',
+ 'Section' => 'array',
+ 'StudentData' => 'array',
+ 'Maps' => 'array');
+ &Apache::loncommon::store_course_settings('statistics',
+ \%Saveable_Parameters);
+ &Apache::loncommon::restore_course_settings('statistics',
+ \%Saveable_Parameters);
+ #
+ &Apache::lonstatistics::PrepareClasslist();
+ #
+ # Clear the package variables
+ undef(@StatsArray);
+ #
+ # Finally let the user know we are here
+ my $interface = &CreateInterface();
+ $r->print($interface);
+ $r->print('');
+ #
+ if (! exists($ENV{'form.statsfirstcall'})) {
+ $r->print('');
+ $r->print('
'.
+ &mt('Press "Generate Statistics" when you are ready.').
+ '
'.
+ &mt('It may take some time to update the student data '.
+ 'for the first analysis. Future analysis this session '.
+ ' will not have this delay.').
+ '
';
+sub compute_discrimination_factor {
+ my ($resource,$part,$sequence) = @_;
+ my @Resources;
+ foreach my $res (@{$sequence->{'contents'}}) {
+ next if ($res->{'symb'} eq $resource->{'symb'});
+ push (@Resources,$res->{'symb'});
}
- return $row;
+ #
+ # rank
+ my $ranking =
+ &Apache::loncoursedata::rank_students_by_scores_on_resources
+ (\@Resources,
+ \@Apache::lonstatistics::SelectedSections,
+ $Apache::lonstatistics::enrollment_status,undef);
+ #
+ # compute their percent scores on the problems in the sequence,
+ my $number_to_grab = int(scalar(@{$ranking})/4);
+ my $num_students = scalar(@{$ranking});
+ my @BottomSet = map { $_->[&Apache::loncoursedata::RNK_student()];
+ } @{$ranking}[0..$number_to_grab];
+ my @TopSet =
+ map {
+ $_->[&Apache::loncoursedata::RNK_student()];
+ } @{$ranking}[($num_students-$number_to_grab)..($num_students-1)];
+ my ($bottom_sum,$bottom_max) =
+ &Apache::loncoursedata::get_sum_of_scores($resource,$part,\@BottomSet);
+ my ($top_sum,$top_max) =
+ &Apache::loncoursedata::get_sum_of_scores($resource,$part,\@TopSet);
+ my $deg_of_disc;
+ if ($top_max == 0 || $bottom_max==0) {
+ $deg_of_disc = 'nan';
+ } else {
+ $deg_of_disc = ($top_sum/$top_max) - ($bottom_sum/$bottom_max);
+ }
+ #&Apache::lonnet::logthis(' '.$top_sum.'/'.$top_max.
+ # ' - '.$bottom_sum.'/'.$bottom_max);
+ return $deg_of_disc;
}
-
###############################################
###############################################
-sub BuildGraphicChart {
- my ($graph,$cacheDB,$courseDescription,$students,$courseID,$r,$c)=@_;
- my %cache;
- my $max;
- my $title = '';
- if($graph eq 'DoDiffGraph') {
- $title = 'Degree-of-Difficulty';
- } else {
- $title = 'Wrong-Percentage';
- }
- my $currentSequence = -1;
- my $sortProblems = 'Sort Within Sequence';
- my ($result, $orderedProblems) =
- &InitializeProblemStatistics($cacheDB, $students, $courseID, $c, $r);
- if($result ne 'OK') {
+=pod
+
+=item ProblemStatisticsLegend
+
+=over 4
+
+=item #Stdnts
+Total number of students attempted the problem.
+
+=item Tries
+Total number of tries for solving the problem.
+
+=item Max Tries
+Largest number of tries for solving the problem by a student.
+
+=item Mean
+Average number of tries. [ Tries / #Stdnts ]
+
+=item #YES
+Number of students solved the problem correctly.
+
+=item #yes
+Number of students solved the problem by override.
+
+=item %Wrong
+Percentage of students who tried to solve the problem
+but is still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]
+
+=item DoDiff
+Degree of Difficulty of the problem.
+[ 1 - ((#YES+#yes) / Tries) ]
+
+=item S.D.
+Standard Deviation of the tries.
+[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1)
+where Xi denotes every student\'s tries ]
+
+=item Skew.
+Skewness of the students tries.
+[(sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3)]
+
+=item Dis.F.
+Discrimination Factor: A Standard for evaluating the
+problem according to a Criterion
+
+=item [Criterion to group students into %27 Upper Students -
+and %27 Lower Students]
+1st Criterion for Sorting the Students:
+Sum of Partial Credit Awarded / Total Number of Tries
+2nd Criterion for Sorting the Students:
+Total number of Correct Answers / Total Number of Tries
+
+=item Disc.
+Number of Students had at least one discussion.
+
+=back
+
+=cut
+
+
+############################################################
+############################################################
+##
+## How this all works:
+## Statistics are computed by calling &get_statistics with the sequence,
+## resource, and part id to run statistics on. At various places within
+## the loops which compute the statistics, as well as before and after
+## the entire process, subroutines can be called. The subroutines are
+## registered to the following hooks:
+##
+## hook subroutine inputs
+## ----------------------------------------------------------
+## pre $r,$count
+## pre_seq $r,$count,$seq
+## pre_res $r,$count,$seq,$res
+## calc $r,$count,$seq,$res,$data
+## post_res $r,$count,$seq,$res
+## post_seq $r,$count,$seq
+## post $r,$count
+##
+## abort $r
+##
+## subroutines will be called in the order in which they are registered.
+##
+############################################################
+############################################################
+{
+
+my %hooks;
+my $aborted = 0;
+
+sub abort_computation {
+ $aborted = 1;
+}
+
+sub clear_hooks {
+ $aborted = 0;
+ undef(%hooks);
+}
+
+sub register_hook {
+ my ($hookname,$subref)=@_;
+ if ($hookname !~ /^(pre|pre_seq|pre_res|post|post_seq|post_res|calc)$/){
return;
}
- my @values = ();
- unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
- return 'Unable to tie database.7';
- }
- foreach(@$orderedProblems) {
- my ($sequence,$problem,$part)=split(':', $_);
- if($cache{'StatisticsMaps'} ne 'All Maps' &&
- $cache{'StatisticsMaps'} ne $cache{$sequence.':title'}) {
- next;
- }
- if( $currentSequence == -1 ||
- ($sortProblems eq 'Sort Within Sequence' &&
- $currentSequence != $sequence)) {
- if($currentSequence != -1) {
- &DrawGraph(\@values,$courseDescription,$title,$max,$r);
- }
- if($sortProblems eq 'Sort Within Sequence') {
- $r->print(' '.$cache{$sequence.':title'}.''."\n");
- }
- $currentSequence = $sequence;
- @values = ();
- $max=0;
- }
- my $data = 0;
- if($graph eq 'DoDiffGraph') {
- $data = sprintf("%.2f", $cache{$_.':degreeOfDifficulty'}),
+ if (ref($subref) ne 'CODE') {
+ &Apache::lonnet::logthis('attempt to register hook to non-code: '.
+ $hookname,' = '.$subref);
+ } else {
+ if (exists($hooks{$hookname})) {
+ push(@{$hooks{$hookname}},$subref);
} else {
- $data = sprintf("%.1f", $cache{$_.':percentWrong'}),
- }
- if($max < $data) {
- $max = $data;
+ $hooks{$hookname} = [$subref];
}
- push(@values, $data);
}
- untie(%cache);
- &DrawGraph(\@values,$courseDescription,$title,$max,$r);
return;
}
-sub DrawGraph {
- my ($values,$courseDescription,$title,$Max,$r)=@_;
- my $sendValues = join(',', @$values);
- my $sendCount = scalar(@$values);
- $r->print(" The Maximum Value is: $Max");
- if ( $Max > 1 ) {
- if ($Max % 10) {
- if ( int($Max) < $Max ) {
- $Max++;
- $Max = int($Max);
- }
- }
- #(10 - $Max % 10);
- } else { $Max = 1; }
- my @GData = ('','Problem_number',$title,$Max,$sendCount,$sendValues);
-# $r->print(''."\n");
- $r->print(' '."\n");
- $r->print('');
-# $r->print('