--- loncom/interface/statistics/lonstudentassessment.pm 2002/07/24 14:52:32 1.1
+++ loncom/interface/statistics/lonstudentassessment.pm 2003/01/09 16:37:48 1.26
@@ -1,12 +1,11 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonstudentassessment.pm,v 1.1 2002/07/24 14:52:32 stredwic Exp $
+# $Id: lonstudentassessment.pm,v 1.26 2003/01/09 16:37:48 minaeibi Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
-#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -31,209 +30,435 @@
# 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
# YEAR=2002
# 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26,4/7,5/6 Behrouz Minaei
-# 5/12,5/14,5/15,5/19,5/26,7/16 Behrouz Minaei
+# 5/12,5/14,5/15,5/19,5/26,7/16,12/24 Behrouz Minaei
#
###
-package Apache::lonstudentassessment;
+package Apache::lonstudentassessment;
use strict;
use Apache::lonhtmlcommon;
use Apache::loncoursedata;
use GDBM_File;
-sub BuildStudentAssessmentPage {
- my ($cacheDB, $students, $courseID, $c)=@_;
+#my $jr;
+sub BuildStudentAssessmentPage {
+ my ($cacheDB,$students,$courseID,$formName,$headings,$spacing,
+ $studentInformation,$r,$c)=@_;
+# $jr = $r;
my %cache;
-
- my $Ptr = '';
- $Ptr .= '
'."\n";
+
+ return $Str;
+}
+
+=pod
+
+=item &FormatStudentData()
+
+First, FormatStudentInformation is called and prefixes the course information.
+This function produces a formatted string of the student\'s course information.
+Each column of data represents all the problems for a given sequence. For
+valid grade data, a link is created for that problem to a submission record
+for that problem.
+
+=over 4
+
+Input: $name, $studentInformation, $ChartDB
+
+$name: The name and domain of the current student in name:domain format
+
+$studentInformation: A pointer to an array holding the names used to
+remove data from the hash. They represent
+the name of the data to be removed.
+
+$ChartDB: The name of the cached data database which will be tied to that
+database.
+
+Output: $Str
+
+$Str: Formatted string that is an entire row of the chart. It is a
+concatenation of student information and student course information.
+
+=back
+
+=cut
+
sub StudentReport {
- my ($cache, $name)=@_;
+ my ($cache,$name,$spacing,$showSequences)=@_;
+ my ($username,$domain)=split(':',$name);
my $Str = '';
+ if(defined($cache->{$name.':error'})) {
+ return $Str;
+ }
if($cache->{$name.':error'} =~ /course/) {
- my ($username)=split(':',$name);
$Str .= 'No course data for student ';
$Str .= ''.$username.'. ';
return $Str;
}
- $Str .= "
\#
Set Title
";
- $Str .= '
Results
Tries
'."\n";
+ my $hasVersion = 'false';
+ my $hasFinalData = 'false';
+ foreach my $sequence (@$showSequences) {
+ my $hasData = 'false';
+ my $characterCount=0;
+ foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
+ my $problem = $cache->{$problemID.':problem'};
+ # All grades (except for versionless parts) are displayed as links
+ # to their submission record. Loop through all the parts for the
+ # current problem in the correct order and prepare the output links
+ foreach(split(/\:/,$cache->{$sequence.':'.$problemID.
+ ':parts'})) {
+ if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
+ $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
+ $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
+ $Str .= ' ';
+ $characterCount++;
+ next;
+ }
+ $hasVersion = 'true';
+ $hasData = 'true';
+ if (lc($ENV{'form.displaymode'}) ne 'display without links') {
+ $Str .= '';
+ }
+ my $code = $cache->{$name.':'.$problemID.':'.$_.':code'};
+ my $tries = $cache->{$name.':'.$problemID.':'.$_.':tries'};
+ if($code eq '*' && $tries < 10 && $tries ne '') {
+ $code = $tries;
+ }
+ $Str .= $code;
+ if (lc($ENV{'form.displaymode'}) ne 'display without links') {
+ $Str .= '';
+ }
+ $characterCount++;
+ }
+ }
- my $codes;
- my $attempts;
- foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
- if($cache->{'StudentAssessmentMap'} ne 'All Maps' &&
- $cache->{'StudentAssessmentMap'} ne $cache->{$sequence.':title'}) {
- next;
+ # Output the number of correct answers for the current sequence.
+ # This part takes up 6 character slots, but is formated right
+ # justified.
+ my $spacesNeeded=$cache->{$sequence.':columnWidth'}-$characterCount;
+ $spacesNeeded -= 3;
+ $Str .= (' 'x$spacesNeeded);
+
+# my $outputProblemsCorrect = sprintf("%3d", $cache->{$name.':'.$sequence.
+# ':problemsCorrect'});
+
+ my $outputProblemsCorrect = sprintf("%2d/%2d", $cache->{$name.':'.$sequence.
+ ':problemsCorrect'},
+ $characterCount);
+ if($hasData eq 'true') {
+ $Str .= ''.$outputProblemsCorrect.'';
+ $hasFinalData = 'true';
+ } else {
+ $Str .= ' ';
}
+ $Str .= $spacing;
+ }
- $Str .= '
'.$sequence.'
';
- $Str .= '
'.$cache->{$sequence.':title'}.'
';
+ # Output the total correct problems over the total number of problems.
+ # I don't like this type of formatting, but it is a solution. Need
+ # a way to dynamically determine the space requirements.
+ my $outputProblemsSolved = sprintf("%4d", $cache->{$name.':problemsSolved'});
+ my $outputTotalProblems = sprintf("%4d", $cache->{$name.':totalProblems'});
+ if($hasFinalData eq 'true') {
+ $Str .= ''.$outputProblemsSolved.
+ ' / '.$outputTotalProblems.'';
+ } else {
+ $Str .= ' ';
+ }
+
+ if($hasVersion eq 'false') {
+ $Str = 'No course data.';
+ }
+
+ return $Str;
+}
- $codes = '';
- $attempts = '';
- foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
- my $problem = $cache->{$problemID.':problem'};
- my $LatestVersion = $cache->{$name.':version:'.$problem};
- # Output dashes for all the parts of this problem if there
- # is no version information about the current problem.
- if(!$LatestVersion) {
- foreach my $part (split(/\:/,$cache->{$sequence.':'.
- $problemID.
- ':parts'})) {
- $codes .= "-,";
- $attempts .= "0,";
- }
- next;
- }
-
- my %partData=undef;
- # Initialize part data, display skips correctly
- # Skip refers to when a student made no submissions on that
- # part/problem.
- foreach my $part (split(/\:/,$cache->{$sequence.':'.
- $problemID.
- ':parts'})) {
- $partData{$part.':tries'}=0;
- $partData{$part.':code'}='-';
- }
-
- # Looping through all the versions of each part, starting with the
- # oldest version. Basically, it gets the most recent
- # set of grade data for each part.
- for(my $Version=1; $Version<=$LatestVersion; $Version++) {
- foreach my $part (split(/\:/,$cache->{$sequence.':'.
- $problemID.
- ':parts'})) {
-
- if(!defined($cache->{$name.":$Version:$problem".
- ":resource.$part.solved"})) {
- # No grade for this submission, so skip
- next;
- }
-
- my $tries=0;
- my $code='U';
-
- $tries = $cache->{$name.":$Version:$problem".
- ":resource.$part.tries"};
- $partData{$part.':tries'}=($tries) ? $tries : 0;
-
- my $val = $cache->{$name.":$Version:$problem".
- ":resource.$part.solved"};
- if ($val eq 'correct_by_student') {$code = 'Y';}
- elsif ($val eq 'correct_by_override') {$code = 'y';}
- elsif ($val eq 'incorrect_attempted') {$code = 'N';}
- elsif ($val eq 'incorrect_by_override'){$code = 'N';}
- elsif ($val eq 'excused') {$code = 'x';}
- $partData{$part.':code'}=$code;
- }
- }
-
- # Loop through all the parts for the current problem in the
- # correct order and prepare the output
- foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
- ':parts'})) {
- $codes .= $partData{$_.':code'}.',';
- $attempts .= $partData{$_.':tries'}.',';
- }
- }
- $codes =~ s/,$//;
- $attempts =~ s/,$//;
- $Str .= '
'."\n";
+ foreach my $S(@$sequenceKeys) {
+ my $title=$cache->{$S.':title'};
+ #$Str .= $cache->{$S.':problems'};
+ #my @problems=split(':', $cache->{$S.':problems'});
+ #my $pCount=scalar @problems;
+ my $pCount=MaxSeqPr($cache,@$students[0],$S);
+ my $crr;
+ if ($StudentCount) {
+ $crr=sprintf( "%.2f", $Correct{$S}/$StudentCount );
+ } else {
+ $crr="0.00";
+ }
+ $Str .= '
'.$title.
+ '
'.$pCount.
+ '
'.$crr.
+ '
'."\n";
}
$Str .= '
'."\n";
@@ -241,6 +466,259 @@ sub StudentReport {
return $Str;
}
+
+
+sub MaxSeqPr {
+ my ($cache, $name, $sequence)=@_;
+ my $prCount=0;
+ foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
+ my $problem = $cache->{$problemID.':problem'};
+ foreach(split(/\:/,$cache->{$sequence.':'.$problemID.':parts'})) {
+ if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
+ $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
+ $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
+ $prCount++;
+ next;
+ }
+ $prCount++;
+ }
+ }
+ return $prCount;
+}
+
+
+
+
+
+=pod
+
+=item &CreateLegend()
+
+This function returns a formatted string containing the legend for the
+chart. The legend describes the symbols used to represent grades for
+problems.
+
+=cut
+
+sub CreateLegend {
+ my $Str = "
".
+ " 1 correct by student in 1 try\n".
+ " 7 correct by student in 7 tries\n".
+ " * correct by student in more than 9 tries\n".
+ " + correct by hand grading or override\n".
+ " - incorrect by override\n".
+ " . incorrect attempted\n".
+ " # ungraded attempted\n".
+ " not attempted (blank field)\n".
+ " x excused".
+ "
";
+ return $Str;
+}
+
+=pod
+
+=item &CreateColumnSelectionBox()
+
+If there are columns not being displayed then this selection box is created
+with a list of those columns. When selections are made and the page
+refreshed, the columns will be removed from this box and the column is
+put back in the chart. If there is no columns to select, no row is added
+to the interface table.
+
+=over 4
+Input: $CacheData, $headings
+
+
+$CacheData: A pointer to a hash tied to the cached data
+
+$headings: An array of the names of the columns for the student information.
+They are used for displaying which columns are missing.
+
+Output: $notThere
+
+$notThere: The string contains one row of a table. The first column has the
+name of the selection box. The second contains the selection box
+which has a size of four.
+
+=back
+
+=cut
+
+sub CreateColumnSelectionBox {
+ my ($doNotShow)=@_;
+
+ my $notThere = '';
+ $notThere .= '';
+
+ return $notThere;
+}
+
+=pod
+
+=item &CreateColumnSelectors()
+
+This function generates the checkboxes above the column headings. The
+column will be removed if the checkbox is unchecked.
+
+=over 4
+
+Input: $CacheData, $headings
+
+$CacheData: A pointer to a hash tied to the cached data
+
+$headings: An array of the names of the columns for the student
+information. They are used to know what are the student information columns
+
+Output: $present
+
+$present: The string contains the first row of a table. Each column contains
+a checkbox which is left justified. Currently left justification is used
+for consistency of location over the column in which it presides.
+
+=back
+
+=cut
+
+sub CreateColumnSelectors {
+ my ($infoHeadings, $sequenceHeadings, $sequenceKeys)=@_;
+
+ my $present = '';
+ for(my $index=0; $index<(scalar @$infoHeadings); $index++) {
+ $present .= '