[LON-CAPA-cvs] cvs: loncom / lond /interface loncoursedata.pm lonhtmlcommon.pm lonstatistics.pm /interface/statistics lonproblemanalysis.pm lonproblemstatistics.pm lonstudentassessment.pm
stredwic
lon-capa-cvs@mail.lon-capa.org
Tue, 13 Aug 2002 00:37:18 -0000
This is a MIME encoded message
--stredwic1029199038
Content-Type: text/plain
stredwic Mon Aug 12 20:37:18 2002 EDT
Modified files:
/loncom lond
/loncom/interface loncoursedata.pm lonhtmlcommon.pm
lonstatistics.pm
/loncom/interface/statistics lonproblemanalysis.pm
lonproblemstatistics.pm
lonstudentassessment.pm
Log:
First, added unescaping of $key in lond dump command.
Next, I added a new way to download student course data. There are now
two functions for storing data, DownloadStudentCourseData and
DownloadStudentCourseDataSeparate. These two functions base their running
on input parameters. The option parameters are whether or not to check
the date for downloading, whether or not to store all the dumped data or
extract out the data you want, whether or not to display a status window.
The extracting data parameter will be best utilized if someone adds in the
ability to send a list of what parameters are desired and perhaps some simple
commands to affect how that data is processed, like tries, sum would
sum record the sum of all the tries for a student. This is just an idea.
Currently, I have all the statistics modules using the extract ability.
This slightly increases in download time, but drastically reduces cache
size. Possible ideas include pushing the extract to the lond side with a
list of parameter/commands, or even downloading everything to a temp cache,
then extract the necessary data into the cache then removing the temp
cache. There are lots of other possibilities, which can change the download
time, cache size, and other factors. Now, only loncoursedata handles the
downloading of data to a hash.
lonstudentassessment was changed slightly to remove ' ' as a link if the
student actually hadn't attempted the problem.
lonproblemanalysis was updated for the new str2hash type functions. There
are a couple of (cludges/fixes) for it. Depending on whether or not the
str2hash type functions are changed, these may or may not need to be
updated.
lonproblemstatistics was drastically overhauled. Most of the processing
was removed. Now, it just does its few statistics functions and outputs
the table. Currently, I broke the graph, discussion column, and
discriminant factor columns. These will be fixed on the next commit soon.
There is also no caching done. This will also be remedied soon. The
problem that will need attention with caching is to know when to update
the statistics cached data when a student's course data is updated.
Lastly, I plan to add perhaps a toggle legend display button, another graph
button(percentage correct), a button to send the CSV format(not just display),
and add a toggle button for sorting within a sequence and sorting all
the problems.
Also, I changed the look and feel to be the same as the class list page.
Also, the displaying of sequence headers and child sequences are not
working. This will be fixed, but thought will be put into how best to
make it look and have a similiar fill for all the table combinations.
--stredwic1029199038
Content-Type: text/plain
Content-Disposition: attachment; filename="stredwic-20020812203718.txt"
Index: loncom/lond
diff -u loncom/lond:1.89 loncom/lond:1.90
--- loncom/lond:1.89 Fri Aug 9 14:18:36 2002
+++ loncom/lond Mon Aug 12 20:37:18 2002
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.89 2002/08/09 18:18:36 www Exp $
+# $Id: lond,v 1.90 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1214,10 +1214,12 @@
my $proname=propath($udom,$uname);
my $qresult='';
if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
+ study($regexp);
foreach $key (keys %hash) {
- if (eval('$key=~/$regexp/')) {
+ my $unescapeKey = &unescape($key);
+ if (eval('$unescapeKey=~/$regexp/')) {
$qresult.="$key=$hash{$key}&";
- }
+ }
}
if (untie(%hash)) {
$qresult=~s/\&$//;
Index: loncom/interface/loncoursedata.pm
diff -u loncom/interface/loncoursedata.pm:1.12 loncom/interface/loncoursedata.pm:1.13
--- loncom/interface/loncoursedata.pm:1.12 Mon Aug 5 10:16:19 2002
+++ loncom/interface/loncoursedata.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: loncoursedata.pm,v 1.12 2002/08/05 14:16:19 stredwic Exp $
+# $Id: loncoursedata.pm,v 1.13 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -51,6 +51,7 @@
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet();
+use Apache::lonhtmlcommon;
use HTML::TokeParser;
use GDBM_File;
@@ -190,9 +191,9 @@
$courseID.'.db',
$Apache::lonnet::perlvar{'lonUsersDir'});
- if($lastDownloadTime >= $modifiedTime) {
- $courseData{'lastDownloadTime'}=time;
- $courseData{'UpToDate'} = 'true';
+ if($lastDownloadTime >= $modifiedTime && $modifiedTime >= 0) {
+ $courseData{$namedata.':lastDownloadTime'}=time;
+ $courseData{$namedata.':UpToDate'} = 'true';
return \%courseData;
}
@@ -203,7 +204,13 @@
%courseData=&Apache::lonnet::dump($courseID, $domain, $name, $WhatIWant);
$courseData{'UpToDate'} = 'false';
$courseData{'lastDownloadTime'}=time;
- return \%courseData;
+
+ my %newData;
+ foreach (keys(%courseData)) {
+ $newData{$namedata.':'.$_} = $courseData{$_};
+ }
+
+ return \%newData;
}
# ----- END DOWNLOAD INFORMATION ---------------------------------------
@@ -281,11 +288,7 @@
$currentSequence=-1;
my $topLevelSequenceNumber = $currentSequence;
- my $problemCount=0;
- my $problemCount2=0;
my %sequenceRecord;
- my $sequenceCount=0;
- my $sequenceCount2=0;
while(1) {
if($c->aborted()) {
last;
@@ -294,7 +297,6 @@
#if page || sequence
if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}}) &&
!defined($sequenceRecord{$currentResourceID})) {
- $sequenceCount++;
$sequenceRecord{$currentResourceID}++;
push(@sequences, $currentSequence);
push(@currentResource, $currentResourceID);
@@ -332,15 +334,11 @@
$currentResourceID=~/(\d+)\.(\d+)/;
my $partA=$1;
my $partB=$2;
- if($hash{'src_'.$currentResourceID}=~/\.problem$/) {
- $problemCount++;
- }
if($hash{'src_'.$currentResourceID}=~
/\.(problem|exam|quiz|assess|survey|form)$/ &&
$partA eq $currentSequence &&
!defined($sequenceRecord{$currentSequence.':'.
$currentResourceID})) {
- $problemCount2++;
$sequenceRecord{$currentSequence.':'.$currentResourceID}++;
my $Problem = &Apache::lonnet::symbclean(
&Apache::lonnet::declutter($hash{'map_id_'.$partA}).
@@ -416,7 +414,6 @@
$lastResourceID=pop(@finishResource);
if(defined($cache->{$currentSequence.':problems'})) {
- $sequenceCount2++;
# Capture sequence information here
$cache->{$currentSequence.':title'}=
$hash{'title_'.$currentResourceID};
@@ -481,10 +478,6 @@
$currentResourceID=pop(@currentResource);
}
- $cache->{'jasoncount'}=$problemCount;
- $cache->{'jasoncount2'}=$problemCount2;
- $cache->{'jasonseq'}=$sequenceCount;
- $cache->{'jasonseq2'}=$sequenceCount2;
unless (untie(%hash)) {
&Apache::lonnet::logthis("<font color=blue>WARNING: ".
"Could not untie coursemap $fn (browse)".
@@ -662,42 +655,170 @@
sub ProcessStudentData {
my ($cache,$courseData,$name)=@_;
- if($courseData->{'UpToDate'} eq 'true') {
- $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};
- if($courseData->{'lastDownloadTime'} eq 'Not downloaded') {
- $cache->{$name.':updateTime'} = ' Not updated';
- } else {
- $cache->{$name.':updateTime'}=
- localtime($courseData->{'lastDownloadTime'});
- }
+ if(!&CheckDateStampError($courseData, $cache, $name)) {
return;
}
- my @courseKeys = keys(%$courseData);
-
- foreach (@courseKeys) {
- if(/^(con_lost|error|no_such_host)/i) {
- $cache->{$name.':error'}='Could not download course data.';
- return;
- }
+ foreach (keys %$courseData) {
+ $cache->{$_}=$courseData->{$_};
}
- $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};
- if($courseData->{'lastDownloadTime'} eq 'Not downloaded') {
- $cache->{$name.':updateTime'} = ' Not updated';
- } else {
- $cache->{$name.':updateTime'}=
- localtime($courseData->{'lastDownloadTime'});
+ return;
+}
+
+sub ExtractStudentData {
+ my ($input, $output, $data, $name)=@_;
+
+ if(!&CheckDateStampError($input, $data, $name)) {
+ return;
}
- foreach (@courseKeys) {
- $cache->{$name.':'.$_}=$courseData->{$_};
+
+ my ($username,$domain)=split(':',$name);
+
+ my $Version;
+ my $problemsCorrect = 0;
+ my $totalProblems = 0;
+ my $problemsSolved = 0;
+ my $numberOfParts = 0;
+ foreach my $sequence (split(':', $data->{'orderedSequences'})) {
+ foreach my $problemID (split(':', $data->{$sequence.':problems'})) {
+ my $problem = $data->{$problemID.':problem'};
+ my $LatestVersion = $input->{$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(/\:/,$data->{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+ $totalProblems++;
+ }
+ $output->{$name.':'.$problemID.':NoVersion'} = 'true';
+ 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(/\:/,$data->{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+ $partData{$part.':tries'}=0;
+ $partData{$part.':code'}=' ';
+ $partData{$part.':awarded'}=0;
+ $partData{$part.':timestamp'}=0;
+ foreach my $response (split(':', $data->{$sequence.':'.
+ $problemID.':'.
+ $part.':responseIDs'})) {
+ $partData{$part.':'.$response.':submission'}='';
+ }
+ }
+
+ # 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.
+ my @submissions = ();
+ for(my $Version=1; $Version<=$LatestVersion; $Version++) {
+ foreach my $part (split(/\:/,$data->{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+
+ if(!defined($input->{"$name:$Version:$problem".
+ ":resource.$part.solved"})) {
+ # No grade for this submission, so skip
+ next;
+ }
+
+ my $tries=0;
+ my $code=' ';
+ my $awarded=0;
+
+ $tries = $input->{$name.':'.$Version.':'.$problem.
+ ':resource.'.$part.'.tries'};
+ $awarded = $input->{$name.':'.$Version.':'.$problem.
+ ':resource.'.$part.'.awarded'};
+
+ $partData{$part.':awarded'}=($awarded) ? $awarded : 0;
+ $partData{$part.':tries'}=($tries) ? $tries : 0;
+
+ $partData{$part.':timestamp'}=$input->{$name.':'.$Version.':'.
+ $problem.
+ ':timestamp'};
+ if(!$input->{$name.':'.$Version.':'.$problem.':resource.'.$part.
+ '.previous'}) {
+ foreach my $response (split(':',
+ $data->{$sequence.':'.
+ $problemID.':'.
+ $part.':responseIDs'})) {
+ @submissions=($input->{$name.':'.$Version.':'.
+ $problem.
+ ':resource.'.$part.'.'.
+ $response.'.submission'},
+ @submissions);
+ }
+ }
+
+ my $val = $input->{$name.':'.$Version.':'.$problem.
+ ':resource.'.$part.'.solved'};
+ if ($val eq 'correct_by_student') {$code = '*';}
+ elsif ($val eq 'correct_by_override') {$code = '+';}
+ elsif ($val eq 'incorrect_attempted') {$code = '.';}
+ elsif ($val eq 'incorrect_by_override'){$code = '-';}
+ elsif ($val eq 'excused') {$code = 'x';}
+ elsif ($val eq 'ungraded_attempted') {$code = '#';}
+ else {$code = ' ';}
+ $partData{$part.':code'}=$code;
+ }
+ }
+
+ foreach my $part (split(/\:/,$data->{$sequence.':'.$problemID.
+ ':parts'})) {
+ $output->{$name.':'.$problemID.':'.$part.':wrong'} =
+ $partData{$part.':tries'};
+
+ if($partData{$part.':code'} eq '*') {
+ $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
+ $problemsCorrect++;
+ } elsif($partData{$part.':code'} eq '+') {
+ $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
+ $problemsCorrect++;
+ }
+
+ $output->{$name.':'.$problemID.':'.$part.':tries'} =
+ $partData{$part.':tries'};
+ $output->{$name.':'.$problemID.':'.$part.':code'} =
+ $partData{$part.':code'};
+ $output->{$name.':'.$problemID.':'.$part.':awarded'} =
+ $partData{$part.':awarded'};
+ $output->{$name.':'.$problemID.':'.$part.':timestamp'} =
+ $partData{$part.':timestamp'};
+ foreach my $response (split(':', $data->{$sequence.':'.
+ $problemID.':'.
+ $part.':responseIDs'})) {
+ $output->{$name.':'.$problemID.':'.$part.':'.$response.
+ ':submission'}=join(':::',@submissions);
+ }
+
+ if($partData{$part.':code'} ne 'x') {
+ $totalProblems++;
+ }
+ }
+ }
+
+ $output->{$name.':'.$sequence.':problemsCorrect'} = $problemsCorrect;
+ $problemsSolved += $problemsCorrect;
+ $problemsCorrect=0;
}
+ $output->{$name.':problemsSolved'} = $problemsSolved;
+ $output->{$name.':totalProblems'} = $totalProblems;
+
return;
}
sub LoadDiscussion {
- my ( $courseID)=@_;
+ my ($courseID)=@_;
my %Discuss=();
my %contrib=&Apache::lonnet::dump(
$courseID,
@@ -733,6 +854,36 @@
# ----- HELPER FUNCTIONS -----------------------------------------------
+sub CheckDateStampError {
+ my ($courseData, $cache, $name)=@_;
+ if($courseData->{$name.':UpToDate'} eq 'true') {
+ $cache->{$name.':lastDownloadTime'} =
+ $courseData->{$name.':lastDownloadTime'};
+ if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
+ $cache->{$name.':updateTime'} = ' Not updated';
+ } else {
+ $cache->{$name.':updateTime'}=
+ localtime($courseData->{$name.':lastDownloadTime'});
+ }
+ return 0;
+ }
+
+ $cache->{$name.':lastDownloadTime'}=$courseData->{$name.':lastDownloadTime'};
+ if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
+ $cache->{$name.':updateTime'} = ' Not updated';
+ } else {
+ $cache->{$name.':updateTime'}=
+ localtime($courseData->{$name.':lastDownloadTime'});
+ }
+
+ if(defined($courseData->{$name.':error'})) {
+ $cache->{$name.':error'}=$courseData->{$name.':error'};
+ return 0;
+ }
+
+ return 1;
+}
+
=pod
=item &ProcessFullName()
@@ -847,6 +998,215 @@
return $isCached;
}
+sub DownloadStudentCourseData {
+ my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+
+ my $title = 'LON-CAPA Statistics';
+ my $heading = 'Download and Process Course Data';
+ my $studentCount = scalar(@$students);
+ my %cache;
+
+ my $WhatIWant;
+ $WhatIWant = '(^version:(\w|\/|\.|-)+?$|';
+ $WhatIWant .= '^\d+:(\w|\/|\.|-)+?:(resource\.\d+\.';
+ $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
+ $WhatIWant .= '|timestamp)';
+ $WhatIWant .= ')';
+
+ if($status eq 'true') {
+ &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+ }
+ my $count=1;
+ foreach (@$students) {
+ if($c->aborted()) { return 'Aborted'; }
+
+ if($status eq 'true') {
+ my $displayString = $count.'/'.$studentCount.': '.$_;
+ &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+ }
+
+ my $downloadTime='Not downloaded';
+ if($checkDate eq 'true' &&
+ tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+ $downloadTime = $cache{$_.':lastDownloadTime'};
+ untie(%cache);
+ }
+
+ if($c->aborted()) { return 'Aborted'; }
+
+ if($downloadTime eq 'Not downloaded') {
+ my $courseData =
+ &DownloadCourseInformation($_, $courseID, $downloadTime,
+ $WhatIWant);
+ if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+ foreach my $key (keys(%$courseData)) {
+ if($key =~ /^(con_lost|error|no_such_host)/i) {
+ $courseData->{$_.':error'} = 'No course data for '.$_;
+ last;
+ }
+ }
+ if($extract eq 'true') {
+ &ExtractStudentData($courseData, \%cache, \%cache, $_);
+ } else {
+ &ProcessStudentData(\%cache, $courseData, $_);
+ }
+ untie(%cache);
+ } else {
+ next;
+ }
+ }
+ $count++;
+ }
+ if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+ return 'OK';
+}
+
+sub DownloadStudentCourseDataSeparate {
+ my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+ my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
+ my $title = 'LON-CAPA Statistics';
+ my $heading = 'Download Course Data';
+
+ my $WhatIWant;
+ $WhatIWant = '(^version:(\w|\/|\.|-)+?$|';
+ $WhatIWant .= '^\d+:(\w|\/|\.|-)+?:(resource\.\d+\.';
+ $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
+ $WhatIWant .= '|timestamp)';
+ $WhatIWant .= ')';
+
+ &CheckForResidualDownload($courseID, $cacheDB, $students, $c);
+
+ my %cache;
+ my %downloadData;
+ unless(tie(%downloadData,'GDBM_File',$residualFile,&GDBM_NEWDB(),0640)) {
+ return 'Failed to tie temporary download hash.';
+ }
+
+ my $studentCount = scalar(@$students);
+ if($status eq 'true') {
+ &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+ }
+ my $count=1;
+ foreach (@$students) {
+ if($c->aborted()) {
+ untie(%downloadData);
+ return 'Aborted';
+ }
+
+ if($status eq 'true') {
+ my $displayString = $count.'/'.$studentCount.': '.$_;
+ &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+ }
+
+ my $downloadTime='Not downloaded';
+ if($checkDate eq 'true' &&
+ tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+ $downloadTime = $cache{$_.':lastDownloadTime'};
+ untie(%cache);
+ }
+
+ if($c->aborted()) {
+ untie(%downloadData);
+ return 'Aborted';
+ }
+
+ if($downloadTime eq 'Not downloaded') {
+ my $error = 0;
+ my $courseData =
+ &DownloadCourseInformation($_, $courseID, $downloadTime,
+ $WhatIWant);
+ foreach my $key (keys(%$courseData)) {
+ $downloadData{$key} = $courseData->{$key};
+ if($key =~ /^(con_lost|error|no_such_host)/i) {
+ $error = 1;
+ last;
+ }
+ }
+ if($error) {
+ foreach my $deleteKey (keys(%$courseData)) {
+ delete $downloadData{$deleteKey};
+ }
+ $downloadData{$_.':error'} = 'No course data for '.$_;
+ }
+ }
+ $count++;
+ }
+ if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+ return &CheckForResidualDownload($cacheDB, 'true', 'true',
+ $courseID, $r, $c);
+}
+
+sub CheckForResidualDownload {
+ my ($cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+
+ my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
+ if(!-e $residualFile) {
+ return;
+ }
+
+ my %downloadData;
+ my %cache;
+ unless(tie(%downloadData,'GDBM_File',$residualFile,&GDBM_READER(),0640) &&
+ tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+ return;
+ }
+
+ my @dataKeys=keys(%downloadData);
+ my @students=();
+ my %checkStudent;
+ foreach(@dataKeys) {
+ my @temp = split(':', $_);
+ my $student = $temp[0].':'.$temp[1];
+ if(!defined($checkStudent{$student})) {
+ $checkStudent{$student}++;
+ push(@students, $student);
+ }
+ }
+
+ my $heading = 'Process Course Data';
+ my $title = 'LON-CAPA Statistics';
+ my $studentCount = scalar(@students);
+ if($status eq 'true') {
+ &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+ }
+
+ my $count=1;
+ foreach my $name (@students) {
+ last if($c->aborted());
+
+ if($status eq 'true') {
+ my $displayString = $count.'/'.$studentCount.': '.$_;
+ &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+ }
+
+ if($extract eq 'true') {
+ &ExtractStudentData(\%downloadData, \%cache, \%cache, $name);
+ } else {
+ &ProcessStudentData(\%cache, \%downloadData, $name);
+ }
+ foreach (@dataKeys) {
+ if(/^$name/) {
+ delete $downloadData{$_};
+ }
+ }
+ $count++;
+ }
+
+ if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+ untie(%cache);
+ untie(%downloadData);
+
+ if(!$c->aborted()) {
+ my @files = ($residualFile);
+ unlink(@files);
+ }
+
+ return 'OK';
+}
+
sub GetFileTimestamp {
my ($studentDomain,$studentName,$filename,$root)=@_;
$studentDomain=~s/\W//g;
@@ -859,7 +1219,7 @@
$root);
my $fileStat = $dir[0];
my @stats = split('&', $fileStat);
- if(@stats) {
+ if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
return $stats[9];
} else {
return -1;
Index: loncom/interface/lonhtmlcommon.pm
diff -u loncom/interface/lonhtmlcommon.pm:1.6 loncom/interface/lonhtmlcommon.pm:1.7
--- loncom/interface/lonhtmlcommon.pm:1.6 Thu Aug 1 16:49:06 2002
+++ loncom/interface/lonhtmlcommon.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common html routines
#
-# $Id: lonhtmlcommon.pm,v 1.6 2002/08/01 20:49:06 stredwic Exp $
+# $Id: lonhtmlcommon.pm,v 1.7 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -68,7 +68,7 @@
my $selected = 0;
foreach my $sequence (split(':',$data->{'orderedSequences'})) {
$Str .= '<option';
- if($data->{$page.'Map'} eq $data->{$sequence.':title'}) {
+ if($data->{$page.'Maps'} eq $data->{$sequence.':title'}) {
$Str .= ' selected';
$selected = 1;
}
@@ -153,7 +153,7 @@
my ($sections,$selectedSections)=@_;
my $Str = '';
- $Str .= '<select name="Section" multiple="" size="4">'."\n";
+ $Str .= '<select name="Section" multiple="true" size="4">'."\n";
foreach (@$sections) {
$Str .= '<option';
@@ -292,6 +292,38 @@
}
return $Str;
+}
+
+# Create progress
+sub Create_PrgWin {
+ my ($r, $title, $heading)=@_;
+ $r->print('<script>'.
+ "popwin=open(\'\',\'popwin\',\'width=400,height=100\');".
+ "popwin.document.writeln(\'<html><body bgcolor=\"#88DDFF\">".
+ "<title>$title</title>".
+ "<h4>$heading</h4>".
+ "<form name=popremain>".
+ "<input type=text size=35 name=remaining value=Starting></form>".
+ "</body></html>\');".
+ "popwin.document.close();".
+ "</script>");
+
+ $r->rflush();
+}
+
+# update progress
+sub Update_PrgWin {
+ my ($displayString,$r)=@_;
+ $r->print('<script>popwin.document.popremain.remaining.value="'.
+ $displayString.'";</script>');
+ $r->rflush();
+}
+
+# close Progress Line
+sub Close_PrgWin {
+ my ($r)=@_;
+ $r->print('<script>popwin.close()</script>'."\n");
+ $r->rflush();
}
1;
Index: loncom/interface/lonstatistics.pm
diff -u loncom/interface/lonstatistics.pm:1.40 loncom/interface/lonstatistics.pm:1.41
--- loncom/interface/lonstatistics.pm:1.40 Tue Aug 6 13:39:15 2002
+++ loncom/interface/lonstatistics.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonstatistics.pm,v 1.40 2002/08/06 17:39:15 minaeibi Exp $
+# $Id: lonstatistics.pm,v 1.41 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -47,7 +47,6 @@
use Apache::lonproblemanalysis;
use Apache::lonproblemstatistics;
use Apache::lonstudentassessment;
-use Apache::lonchart;
use HTML::TokeParser;
use GDBM_File;
@@ -72,7 +71,8 @@
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['sort','download',
'reportSelected',
- 'StudentAssessmentStudent']);
+ 'StudentAssessmentStudent',
+ 'ProblemStatisticsSort']);
&CheckFormElement($cache, 'Status', 'Status', 'Active');
&CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list');
&CheckFormElement($cache, 'reportSelected', 'reportSelected',
@@ -121,6 +121,8 @@
'ProblemStatisticsAscend', 'Ascending');
&CheckFormElement($cache, 'ProblemStatisticsMaps',
'ProblemStatisticsMaps', 'All Maps');
+ &CheckFormElement($cache, 'ProblemStatisticsSort',
+ 'ProblemStatisticsSort', 'Homework Sets Order');
# Search only form elements
my @headingColumns=();
@@ -356,13 +358,15 @@
$cache{'updateTime:columnWidth'}=24;
if($cache{'download'} ne 'false') {
- my $who = $cache{'download'};
- my $courseData =
- &Apache::loncoursedata::DownloadCourseInformation(
- $who, $courseID,
- $cache{$who.':lastDownloadTime'});
- &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, $who);
+ my @who = ($cache{'download'});
$cache{'download'} = 'false';
+ if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false',
+ $cacheDB, 'true',
+ 'false', $courseID,
+ $r, $c) ne 'OK') {
+ untie(%cache);
+ return 'Stop at download individual';
+ }
} elsif($cache{'DownloadAll'} ne 'false') {
$cache{'DownloadAll'} = 'false';
my @allStudents;
@@ -371,23 +375,14 @@
} else {
@allStudents = split(':::', $cache{'NamesOfStudents'});
}
- &Create_PrgWin($r);
- my $count=1;
- foreach (@allStudents) {
- &Update_PrgWin(scalar(@allStudents),$count,$_,$r);
- my $courseData =
- &Apache::loncoursedata::DownloadCourseInformation(
- $_, $courseID,
- $cache{$_.':lastDownloadTime'});
- &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData,
- $_);
- if($c->aborted()) {
- untie(%cache);
- return 'aborted';
- }
- $count++;
+ if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents,
+ 'false',
+ $cacheDB, 'true',
+ 'true', $courseID,
+ $r, $c) ne 'OK') {
+ untie(%cache);
+ return 'Stop at download all';
}
- &Close_PrgWin($r);
}
if($c->aborted()) {
@@ -400,43 +395,6 @@
return ('OK', $students);
}
-
-# Create progress
-sub Create_PrgWin {
- my ($r)=@_;
- $r->print(<<ENDPOP);
- <script>
- popwin=open('','popwin','width=400,height=100');
- popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
- '<title>LON-CAPA Statistics</title>'+
- '<h4>Computation Progress</h4>'+
- '<form name=popremain>'+
- '<input type=text size=35 name=remaining value=Starting></form>'+
- '</body></html>');
- popwin.document.close();
- </script>
-ENDPOP
-
- $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
- my ($totalStudents,$index,$name,$r)=@_;
- $r->print('<script>popwin.document.popremain.remaining.value="'.
- 'Computing '.$index.'/'.$totalStudents.': '.
- $name.'";</script>');
- $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
- my ($r)=@_;
- $r->print('<script>popwin.close()</script>');
- $r->rflush();
-}
-
-
sub BuildClasslist {
my ($cacheDB,$students,$studentInformation,$headings,$r)=@_;
@@ -556,13 +514,21 @@
my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
"_$ENV{'user.domain'}_$courseID\_statistics.db";
+ $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics'));
+
my ($returnValue, $students) = &PrepareData($c, $cacheDB,
\@studentInformation,
\@headings,$r);
if($returnValue ne 'OK') {
- $r->print('<html><body>'.$returnValue."\n".'</body></html>');
+ $r->print($returnValue."\n".'</body></html>');
return OK;
}
+ if(!$c->aborted()) {
+ &Apache::loncoursedata::CheckForResidualDownload($cacheDB,
+ 'true', 'true',
+ $courseID,
+ $r, $c);
+ }
my $GoToPage;
if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
@@ -578,7 +544,6 @@
$reports{'problem_analysis'} = 'Problem Analysis';
}
- $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics'));
$r->print('<form name="Statistics" ');
$r->print('method="post" action="/adm/statistics">');
$r->print(&CreateMainMenu($cache{'Status'}, \%reports));
Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.4 loncom/interface/statistics/lonproblemanalysis.pm:1.5
--- loncom/interface/statistics/lonproblemanalysis.pm:1.4 Mon Aug 5 16:53:38 2002
+++ loncom/interface/statistics/lonproblemanalysis.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonproblemanalysis.pm,v 1.4 2002/08/05 20:53:38 stredwic Exp $
+# $Id: lonproblemanalysis.pm,v 1.5 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -41,7 +41,7 @@
use Apache::lonnet();
use GDBM_File;
-#my $jr;
+my $jr;
sub BuildProblemAnalysisPage {
my ($cacheDB, $r)=@_;
@@ -64,42 +64,24 @@
sub BuildAnalyzePage {
my ($cacheDB, $students, $courseID,$r)=@_;
-# $jr = $r;
+ $jr = $r;
my $c = $r->connection;
my $Str = '</form>';
my %cache;
- &Create_PrgWin($r);
- my $count=0;
- foreach (@$students) {
- &Update_PrgWin(scalar(@$students),$count,$_,$r);
- if($c->aborted) {
- return $Str;
- }
- my $downloadTime='';
- if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
- $downloadTime = $cache{$_.':lastDownloadTime'};
- untie(%cache);
- }
- if($downloadTime eq 'Not downloaded') {
- my $courseData =
- &Apache::loncoursedata::DownloadCourseInformation($_,
- $courseID);
- if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
- &Apache::loncoursedata::ProcessStudentData(\%cache,
- $courseData, $_);
- untie(%cache);
- } else {
- next;
- }
- }
- $count++;
+ if(&Apache::loncoursedata::DownloadStudentCourseDataSeparate($students, 'true',
+ $cacheDB, 'true',
+ 'true', $courseID,
+ $r, $c) ne 'OK') {
+ $r->print($Str);
+ return;
}
- &Close_PrgWin($r);
+
unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
$Str .= '<html><body>Unable to tie database.</body></html>';
- return $Str;
+ $r->print($Str);
+ return;
}
my ($problemId, $part, $responseId)=split(':',$cache{'AnalyzeInfo'});
@@ -115,11 +97,14 @@
my ($analyzeData) = &InitAnalysis($uri, $part, $responseId, $problem,
$students->[0], $courseID);
if(defined($analyzeData->{'error'})) {
- $Str .= 'Incorrect part requested.<br>';
- return $Str;
+ $Str .= $analyzeData->{'error'}.'<br>Incorrect part requested.<br>';
+ $r->print($Str);
+ return;
}
- if($c->aborted()) { untie(%cache); return $Str; }
+ $r->print($Str);
+ $Str = '';
+ if($c->aborted()) { untie(%cache); return; }
#compute the intervals
&Interval($part, $problem, $interval, $analyzeData->{'concepts'},
@@ -128,37 +113,39 @@
$title =~ s/\ /"_"/eg;
$Str .= '<br><b>'.$uri.'</b>';
- if($c->aborted()) { untie(%cache); return $Str; }
+ $r->print($Str);
+ $Str = '';
+ if($c->aborted()) { untie(%cache); return; }
#Java script Progress window
-# &Create_PrgWin();
-# &Update_PrgWin("Starting-to-analyze-problem");
for(my $index=0; $index<(scalar @$students); $index++) {
- if($c->aborted()) { untie(%cache); return $Str; }
-# &Update_PrgWin($index);
-# &OpStatus($problem, $students->[$index], $courseID, \%ConceptData,
-# $analyzeData->{'foil_to_concept'}, $analyzeData, \%cache);
- &OpStatus($problem, $students->[$index], \%ConceptData,
+ if($c->aborted()) { untie(%cache); return; }
+ &OpStatus($problemId, $students->[$index], \%ConceptData,
$analyzeData->{'foil_to_concept'}, $analyzeData, \%cache);
}
-# &Close_PrgWin();
$Str .= '<br>';
for (my $k=0; $k<$interval; $k++ ) {
if($c->aborted()) { untie(%cache); return $Str; }
$Str .= &DrawGraph($k, $title, $analyzeData->{'concepts'},
\%ConceptData);
+ $r->print($Str);
+ $Str = '';
}
for (my $k=0; $k<$interval; $k++ ) {
if($c->aborted()) { untie(%cache); return $Str; }
$Str .= &DrawTable($k, $analyzeData->{'concepts'}, \%ConceptData);
+ $r->print($Str);
+ $Str = '';
}
my $Answ=&Apache::lonnet::ssi($uri);
$Str .= '<br><b>Here you can see the Problem:</b><br>'.$Answ;
+ $Str .= '<form>';
+ $r->print($Str);
untie(%cache);
- return $Str.'<form>';
+ return;
}
#---- Problem Analysis Web Page ----------------------------------------------
@@ -230,76 +217,29 @@
return $Str;
}
-# Create progress
-sub Create_PrgWin {
- my ($r)=@_;
- $r->print(<<ENDPOP);
- <script>
- popwin=open('','popwin','width=400,height=100');
- popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
- '<title>LON-CAPA Statistics</title>'+
- '<h4>Computation Progress</h4>'+
- '<form name=popremain>'+
- '<input type=text size=35 name=remaining value=Starting></form>'+
- '</body></html>');
- popwin.document.close();
- </script>
-ENDPOP
-
- $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
- my ($totalStudents,$index,$name,$r)=@_;
- $r->print('<script>popwin.document.popremain.remaining.value="'.
- 'Computing '.$index.'/'.$totalStudents.': '.
- $name.'";</script>');
- $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
- my ($r)=@_;
- $r->print('<script>popwin.close()</script>');
- $r->rflush();
-}
-
#---- END Problem Analysis Web Page ------------------------------------------
#---- Analyze Web Page -------------------------------------------------------
#restore the student submissions and finding the result
sub OpStatus {
- my ($problem, $student, $ConceptData, $foil_to_concept,
+ my ($problemID, $student, $ConceptData, $foil_to_concept,
$analyzeData, $cache)=@_;
my $ids = $analyzeData->{'parts'};
my @True = ();
my @False = ();
my $flag=0;
- my $latestVersion = $cache->{$student.':version:'.$problem};
- if(!$latestVersion) {
- return;
- }
my $tries=0;
- for(my $version=1; $version<=$latestVersion; $version++) {
- my $time=$cache->{$student.':'.$version.':'.$problem.':timestamp'};
- foreach my $id (@$ids) {
- my ($currentPart, undef) = split(/\./, $id);
- #check if this is a repeat submission, if so skip it
- next if($cache->{$student.':'.$version.':'.$problem.
- ':resource.'.$currentPart.'.previous'});
- #if no solved this wasn't a real submission, ignore it
- if(!defined($cache->{"$student:$version:$problem".
- ":resource.$currentPart.solved"})) {
- &Apache::lonxml::debug("skipping ");
- next;
- }
- my $Resp = $cache->{$student.':'.$version.':'.$problem.
- ':resource.'.$id.'.submission'};
+ foreach my $id (@$ids) {
+ my ($part, $response) = split(/\./, $id);
+ my $time=$cache->{$student.':'.$problemID.':'.$part.':timestamp'};
+ my @submissions = split(':::', $cache->{$student.':'.$problemID.':'.
+ $part.':'.$response.
+ ':submission'});
+ foreach my $Resp (@submissions) {
my %submission=&Apache::lonnet::str2hash($Resp);
foreach (keys(%submission)) {
if($submission{$_}) {
@@ -441,14 +381,17 @@
'grade_domain' => $domain,
'grade_courseid' => $courseID,
'grade_symb' => $problem));
-
- my %Answer=();
- %Answer=&Apache::lonnet::str2hash($Answ);
+ my ($a)=&Apache::lonnet::str2hashref($Answ);
+ my %b;
+ foreach (keys(%$a)) {
+ $b{&Apache::lonnet::unescape($_)} = $a->{$_};
+ }
+ my $Answer=\%b;
my $found = 0;
my @parts=();
if(defined($responseId)) {
- foreach (@{$Answer{'parts'}}) {
+ foreach (@{$Answer->{'parts'}}) {
if($_ eq $part.'.'.$responseId) {
push(@parts, $_);
$found = 1;
@@ -456,7 +399,7 @@
}
}
} else {
- foreach (@{$Answer{'parts'}}) {
+ foreach (@{$Answer->{'parts'}}) {
if($_ =~ /$part/) {
push(@parts, $_);
$found = 1;
@@ -473,23 +416,23 @@
my @Concepts=();
my %foil_to_concept;
foreach my $currentPart (@parts) {
- if(defined($Answer{$currentPart.'.concepts'})) {
- foreach my $concept (@{$Answer{$currentPart.'.concepts'}}) {
+ if(defined($Answer->{$currentPart.'.concepts'})) {
+ foreach my $concept (@{$Answer->{$currentPart.'.concepts'}}) {
push(@Concepts, $concept);
- foreach my $foil (@{$Answer{$currentPart.'.concept.'.
+ foreach my $foil (@{$Answer->{$currentPart.'.concept.'.
$concept}}) {
$analyzeData{$currentPart.'.foil.value.'.$foil} =
- $Answer{$currentPart.'.foil.value.'.$foil};
+ $Answer->{$currentPart.'.foil.value.'.$foil};
$foil_to_concept{$foil} = $concept;
}
}
} else {
- foreach (keys(%Answer)) {
+ foreach (keys(%$Answer)) {
if(/$currentPart.foil\.value\.(.*)$/) {
push(@Concepts, $1);
$foil_to_concept{$1} = $1;
$analyzeData{$currentPart.'.foil.value.'.$1} =
- $Answer{$currentPart.'.foil.value.'.$1};
+ $Answer->{$currentPart.'.foil.value.'.$1};
}
}
}
Index: loncom/interface/statistics/lonproblemstatistics.pm
diff -u loncom/interface/statistics/lonproblemstatistics.pm:1.18 loncom/interface/statistics/lonproblemstatistics.pm:1.19
--- loncom/interface/statistics/lonproblemstatistics.pm:1.18 Mon Aug 12 14:21:42 2002
+++ loncom/interface/statistics/lonproblemstatistics.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonproblemstatistics.pm,v 1.18 2002/08/12 18:21:42 albertel Exp $
+# $Id: lonproblemstatistics.pm,v 1.19 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -43,11 +43,14 @@
use Apache::loncoursedata;
use GDBM_File;
+my $jr;
sub BuildProblemStatisticsPage {
my ($cacheDB, $students, $courseID, $c, $r)=@_;
my %cache;
+ $jr = $r;
+
unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
return '<html><body>Unable to tie database.</body></html>';
}
@@ -73,345 +76,69 @@
$r->rflush();
untie(%cache);
- &Create_PrgWin($r);
- my $count=0;
- foreach (@$students) {
- &Update_PrgWin(scalar(@$students),$count,$_,$r);
- my $courseData =
- &Apache::loncoursedata::DownloadCourseInformation($_, $courseID);
- last if ($c->aborted());
- if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
- &Apache::loncoursedata::ProcessStudentData(\%cache,
- $courseData, $_);
- untie(%cache);
- }
- $count++;
- }
- &Close_PrgWin($r);
+
+ &Apache::loncoursedata::DownloadStudentCourseDataSeparate($students,'true',
+ $cacheDB,'true',
+ 'true',$courseID,
+ $r, $c);
if($c->aborted()) { return; }
unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
return '<html><body>Unable to tie database.</body></html>';
}
- my %Header = (0,"Homework Sets Order",1,"#Stdnts",2,"Tries",3,"Mod",
- 4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"DoDiff",
- 9,"S.D.",10,"Skew.",11,"D.F.1st",12,"D.F.2nd", 13, "Disc.");
+ my @Header = ("Homework Sets Order","#Stdnts","Tries","Mod",
+ "Mean","#YES","#yes","%Wrng","DoDiff",
+ "S.D.","Skew.","D.F.1st","D.F.2nd","Disc.");
my $color=&setbgcolor(0);
- my $state=$ENV{'form.ProblemStatisticsHeading'};
-
- my $TempCache;
-
- if ($state) {
- $TempCache=&CacheStatisticsTable($state,\%cache,\%Header,
- $r,$color);
- } else {
- my %discriminant=();
- my @list=();
- my %Discuss=&Apache::loncoursedata::LoadDiscussion($courseID);
- my $index=0;
- foreach (@$students) {
- $index++;
- &ExtractStudentData(\%cache, $_, \@list,\%Discuss, $r,
- \%discriminant);
- }
- my ($upper, $lower) = &Discriminant(\%discriminant,$r);
- $TempCache= &BuildStatisticsTable(\%cache, $upper, $lower,
- \@list, \%Header, $students,
- $r, $color);
- }
+# my %Discuss=&Apache::loncoursedata::LoadDiscussion($courseID);
+# my ($upper, $lower) = &Discriminant(\%discriminant,$r);
+ my ($problemData) = &ExtractStudentData(\%cache, $students);
+ &CalculateStatistics($problemData);
+ &SortProblems($problemData, $cache{'ProblemStatisticsSort'},
+ $cache{'ProblemStatisticsAscend'});
+ #$TempCache=
+ &BuildStatisticsTable(\%cache, $cache{'DisplayFormat'},
+ $problemData, \@Header, $r, $color);
untie(%cache);
- foreach (keys %$TempCache) {
- last if ($c->aborted());
- if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
- $cache{$_}=$TempCache->{$_};
+# foreach (keys %$TempCache) {
+# last if ($c->aborted());
+# if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+# $cache{$_}=$TempCache->{$_};
+# untie(%cache);
+# }
+# }
- untie(%cache);
- }
- }
- if($c->aborted()) { return; }
- untie(%cache);
+# if($c->aborted()) { return; }
+# untie(%cache);
+
+ return;
}
#---- Problem Statistics Web Page ---------------------------------------
sub CreateProblemStatisticsTableHeading {
- my ($displayFormat,$sequenceSource,$sequenceTitle,$headings,$r)=@_;
- if($displayFormat eq 'Display CSV Format') {
- $r->print('<br>"'.$sequenceTitle.'","');
- $r->print($sequenceSource.'"');
- return;
- }
- if ($sequenceSource eq 'Sorted by: ') {
- $r->print('<br><b>'.$sequenceSource.$sequenceTitle.'</b>');
- } else {
- $r->print('<br><a href="'.$sequenceSource.
- '" target="_blank">'.$sequenceTitle.'</a>');
- }
- my $Result = "\n".'<table border=2><tr><th>P#</th>'."\n";
- for(my $nIndex=0; $nIndex < (scalar (keys %$headings)); $nIndex++) {
- $Result .= '<th>'.'<input type="submit" name="';
- $Result .= 'ProblemStatisticsHeading" value="';
- $Result .= $headings->{$nIndex}.'" />'.'</th>'."\n";
- }
- $Result .= "\n".'</tr>'."\n";
- $r->print($Result);
- $r->rflush();
-}
-
-sub CloseTable {
- my ($cache,$r)=@_;
- if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
- return;
- }
- $r->print("\n".'</table>'."\n");
- $r->rflush();
-}
-
-
-# Create progress
-sub Create_PrgWin {
- my ($r)=@_;
- $r->print(<<ENDPOP);
- <script>
- popwin=open('','popwin','width=400,height=100');
- popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
- '<title>LON-CAPA Statistics</title>'+
- '<h4>Computation Progress</h4>'+
- '<form name=popremain>'+
- '<input type=text size=35 name=remaining value=Starting></form>'+
- '</body></html>');
- popwin.document.close();
- </script>
-ENDPOP
-
- $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
- my ($totalStudents,$index,$name,$r)=@_;
- $r->print('<script>popwin.document.popremain.remaining.value="'.
- 'Computing '.$index.'/'.$totalStudents.': '.
- $name.'";</script>');
- $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
- my ($r)=@_;
- $r->print('<script>popwin.close()</script>');
- $r->rflush();
-}
-
-
-# ------ Dump the Student's DB file and handling the data for statistics table
-sub ExtractStudentData {
- my ($cache,$name,$list,$Discuss,$r,$discriminant)=@_;
- my $totalTries = 0;
- my $totalAwarded = 0;
- my $spent=0;
- my $spent_yes=0;
- my $TotDiscuss=0;
- my $TotalOpend = 0;
- my $ProbSolved = 0;
- my $ProbTot = 0;
- my $TotFirst = 0;
- my $TimeTot = 0;
- my $Discussed=0;
- my $discrim='';
- my $tempSequenceOrder=100;
-
-#$Apache::lonxml::debug=1;
-#&Apache::lonhomework::showhash(%$cache);
-#$Apache::lonxml::debug=0;
+ my ($headings,$r)=@_;
- foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
- my $tempProblemOrder=100;
- if($cache->{'ProblemStatisticsMaps'} ne 'All Maps' &&
- $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
- next;
- }
- $tempSequenceOrder++;
-
- 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;
- $partData{'count'}=0;
- # 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'})) {
- $tempProblemOrder++;
- $partData{'count'}++;
- $partData{$part.':order'}=$tempProblemOrder;
- $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 $time=0;
- my $awarded=0;
- $Discussed=0;
- my $code='-';
-
- $awarded = $cache->{"$name:$Version:$problem:resource.".
- "$part.awarded"};
- $partData{$part.':awarded'} = ($awarded) ? $awarded : 0;
- $totalAwarded += $awarded;
-
- $tries = $cache->{"$name:$Version:$problem".
- ":resource.$part.tries"};
- $partData{$part.':tries'} = ($tries) ? $tries : 0;
- $partData{$part.':wrong'} = $partData{$part.':tries'};
- $totalTries += $tries;
-
- my $val = $cache->{$name.":$Version:$problem".
- ":resource.$part.solved"};
- if ($val eq 'correct_by_student') {$code = 'C';}
- elsif ($val eq 'correct_by_override') {$code = 'O';}
- elsif ($val eq 'incorrect_attempted') {$code = 'I';}
- elsif ($val eq 'incorrect_by_override'){$code = 'I';}
- elsif ($val eq 'excused') {$code = 'x';}
- $partData{$part.':code'}=$code;
- if($partData{$part.':wrong'} ne 0 &&
- ($code eq 'C' || $code eq 'O')) {
- $partData{$part.':wrong'}--;
- }
- }
- }
-
- # Loop through all the parts for the current problem in the
- # correct order and prepare the output
- my $partCounter=0;
- foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
- ':parts'})) {
- $partCounter++;
- my $Yes = 0;
- if($partData{$_.':code'} eq 'C' ||
- $partData{$_.':code'} eq 'O') {
- $Yes=1;
- }
- my $pOrder=$partData{$_.':order'};
- my $ptr = $tempSequenceOrder.':'.$pOrder.':'.$problemID;
-
- if($partData{'count'} > 1) {
- $ptr .= "*(part $_)";
- }
- $discrim .= '&';
-
- my ($pr_no,$dod)=split('&',$ptr);
-# my $DoDiff=$DoDiff->{$dod};
-# $r->print('<br>'.$name.'---'.$ptr.'==='.$DoDiff);
-
- my $Fac = ($partData{$_.':tries'}) ?
- ($partData{$_.':awarded'}/$partData{$_.':tries'}) : 0;
- my $DisF;
- if($Fac > 0 && $Fac < 1) {
- $DisF = sprintf( "%.4f", $Fac );
- } else {
- $DisF = $Fac;
- }
-
- if ($Discuss->{"$name:$problem"}) {
- $TotDiscuss++;
- $Discussed=1;
- }
- my $time = $cache->{"$name:$LatestVersion:$problem:timestamp"};
- $discrim .= $tempSequenceOrder.'@'.$pOrder.'='.$DisF.'+'.$Yes;
- $ptr .= '&'.$partData{$_.':tries'}.
- '&'.$partData{$_.':wrong'}.
- '&'.$partData{$_.':code'};
- push (@$list, $ptr."&$Discussed");
-# $r->print('<br>'.$_.$name.'---'.$ptr);
-
-#### if ($DoDiff>0.85) {
-
- $TimeTot += $time;
-
- if ($Yes==1 && $partData{$_.':tries'}==1) {
- $TotFirst++;
- }
-# my $Acts= $Activity->{$name.':'.$problem};
-# if ($Acts) {
-# my $Pt=&ProcAct( $Acts, $time );
- #my ($spe,$beg) = split(/\+/,$Pt);
-# my $spe= $Pt;
-# if ($Yes==1) {$spent_yes += $spe;}
-# $spent += $spe;
- #$Beg += $beg;
-# $r->print('<br>'.$name.'---'.$problem.'---'.$spe);
-# }
- $TotalOpend++;
- $ProbTot++;
-
- $tempProblemOrder++;
- }
- }
- }
- my $pstr;
- if($totalTries) {
- my $DisFac = ($totalAwarded/$totalTries);
- my $DisFactor = sprintf( "%.4f", $DisFac );
- my $TS = sprintf( "%.2f", $spent );
- my $TS_yes = sprintf( "%.2f", $spent_yes );
- $pstr=$DisFactor.':'.$name.':'.$ProbTot.':'.$TotalOpend.':'.
- $totalTries.':'.$ProbSolved.':'.$TotFirst.':'.
- $TS_yes.':'.$TS.':'.$TotDiscuss;
- (%$discriminant)->{$pstr}=$discrim;
+ my $Str='';
+ $Str .= '<tr>'."\n";
+ $Str .= '<th bgcolor="#ffffe6">P#</th>'."\n";
+ foreach(@$headings) {
+ $Str .= '<th bgcolor="#ffffe6">'.'<a href="/adm/statistics?reportSelected=';
+ $Str .= &Apache::lonnet::escape('Problem Statistics');
+ $Str .= '&ProblemStatisticsSort=';
+ $Str .= &Apache::lonnet::escape($_).'">'.$_.'</a> </th>'."\n";
}
-}
+ $Str .= "\n".'</tr>'."\n";
-sub NumericSort {
- $a <=> $b;
-}
-
-sub OrderedSort {
- if ($ENV{'form.order'} eq 'Descending') {
- $b <=> $a;
- } else {
- $a <=> $b;
- }
+ return $Str;
}
-
-
sub BuildStatisticsTable {
- my ($cache,$upper,$lower,$list,$headings,$students,$r,$color)=@_;
- my $NoElements = scalar @$list;
- my @list=sort(@$list);
+ my ($cache,$displayFormat,$data,$headings,$r,$color)=@_;
#6666666
# my $file="/home/httpd/perl/tmp/183d.txt";
@@ -427,129 +154,40 @@
##777777
## $Str .= &Classify($discriminantFactor, $students);
- my $p_count = 0;
- my $dummy;
- my $p_val;
- my $ResId;
my %TempCache;
- my $cIdx=0;
-
- foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
- if($cache->{'ProblemStatisticsMaps'} ne 'All Maps' &&
- $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
- next;
- }
- &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'},
- $cache->{$sequence.':source'},
- $cache->{$sequence.':title'},
- $headings,$r);
- my ($tar,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,
- $list[$cIdx]);
- my ($SqOrd,$PrOrd,$Prob)=split(/\:/,$tar);
- $sequence+=100;
- while ($SqOrd==$sequence && $cIdx<$NoElements) {
- my %storestats=();
- my $pOrd=$PrOrd;
- my $Temp = $Prob;
- my $MxTries = 0;
- my $TotalTries = 0;
- my $YES = 0;
- my $Incorrect = 0;
- my $Override = 0;
- my $StdNo = 0;
- my $DiscNo=0;
- my @StdLst;
- while ($pOrd==$PrOrd && $cIdx<$NoElements)
- {
- $cIdx++;
- $StdNo++;
- $StdLst[ $StdNo ] = $Tries;
- $TotalTries += $Tries;
- if ( $MxTries < $Tries ) { $MxTries = $Tries; }
- if ( $Code eq 'C' ){ $YES++; }
- elsif( $Code eq 'I' ) { $Incorrect++; }
- elsif( $Code eq 'O' ) { $Override++; }
- elsif( $Code eq '-' ) { $StdNo--; }
- ($tar,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,
- $list[$cIdx]);
- ($SqOrd,$PrOrd,$Prob)=split(/\:/,$tar);
- }
-
- $p_count++;
- my $Dummy;
- ($ResId,$Dummy)=split(/\*/,$Temp);
- $Temp = '<a href="'.$cache->{$ResId.':source'}.
- '" target="_blank">'.$cache->{$ResId.':title'}.$Dummy.'</a>';
-
-# my $urlres = $cache->{$sequence.':source'});
-#check with Gerd
- #symb of the problem (already decluttered and cleaned)
- my $urlres = $cache->{$ResId.':problem'};
-
-#------------------------ Compute the Average of Tries about one problem
- my $Average = ($StdNo) ? $TotalTries/$StdNo : 0;
-
- $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___timestamp'}=time;
- $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___stdno'}=$StdNo;
- $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___avetries'}=$Average;
-
-#-------------------------------- Compute percentage of Wrong tries
- my $Wrong = ( $StdNo ) ? 100 * ( $Incorrect / $StdNo ) : 0;
-
-#-------------------------------- Compute Standard Deviation
- my $StdDev = 0;
- if ( $StdNo > 1 ) {
- for ( my $n = 0; $n < $StdNo; $n++ ) {
- my $Dif = $StdLst[ $n ]-$Average;
- $StdDev += $Dif*$Dif;
- }
- $StdDev /= ( $StdNo - 1 );
- $StdDev = sqrt( $StdDev );
- }
-
-#-------------------------------- Compute Degree of Difficulty
- my $DoDiff = 0;
- if( $TotalTries > 0 ) {
- $DoDiff = 1 - ( ( $YES + $Override ) / $TotalTries );
-# $DoDiff = ($TotalTries)/($YES + $Override+ 0.1);
- }
-
- $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___difficulty'}=$DoDiff;
-
-#-------------------------------- Compute the Skewness
- my $Skewness = 0;
- my $Sum = 0;
- if ( $StdNo > 0 && $StdDev > 0 ) {
- for ( my $n = 0; $n < $StdNo; $n++ ) {
- my $Dif = $StdLst[ $n ]-$Average;
- $Skewness += $Dif*$Dif*$Dif;
- }
- $Skewness /= $StdNo;
- $Skewness /= $StdDev*$StdDev*$StdDev;
- }
-
-#--------------------- Compute the Discrimination Factors
- my ($Up1,$Up2)=split(/\:/,$upper->{$sequence.'@'.$pOrd});
- my ($Lw1,$Lw2)=split(/\:/,$lower->{$sequence.'@'.$pOrd});
-
- my $Dis1 = $Up1 - $Lw1;
- my $Dis2 = $Up2 - $Lw2;
- my $_D1 = sprintf("%.2f", $Dis1);
- my $_D2 = sprintf("%.2f", $Dis2);
-
-#----------------- Some restition in presenting the float numbers
- my $Avg = sprintf( "%.2f", $Average );
- my $Wrng = sprintf( "%.1f", $Wrong );
- my $SD = sprintf( "%.1f", $StdDev );
- my $DoD = sprintf( "%.2f", $DoDiff );
- my $Sk = sprintf( "%.1f", $Skewness );
- my $join = $sequence.'@'.$pOrd.'&'.$Temp.'&'.$StdNo.'&'.
- $TotalTries.'&'.$MxTries.'&'.$Avg.'&'.
- $YES.'&'.$Override.'&'.$Wrng.'&'.$DoD.'&'.
- $SD.'&'.$Sk.'&'.$_D1.'&'.$_D2.'&'.
- $DiscNo.'&'.$Prob;
+ my $problems = $data->{'problemList'};
+ if($displayFormat ne 'Display CSV Format') {
+ $r->print('<table border="0"><tr><td bgcolor="#777777">'."\n");
+ $r->print('<table border="0" cellpadding="3">'."\n");
+ $r->print(&CreateProblemStatisticsTableHeading($headings, $r));
+ } else {
+ $r->print('<br>');
+ }
- $TempCache{'CacheTable:'.($p_count-1)}=$join;
+ my $count = 1;
+ foreach(@$problems) {
+ my ($sequence,$problem,$part)=split(':', $_);
+# my $problemRef = '<a href="'.$cache->{$problem.':source'}.
+# '" target="_blank">'.$cache->{$problem.':title'}.'</a>';
+
+ my $ref = $cache->{$problem.':title'};
+ my $title = $cache->{$problem.':title'};
+ my $source = 'source';
+ my $tableData = join('&', $ref, $title, $source,
+ $data->{$_.':studentCount'},
+ $data->{$_.':totalTries'},
+ $data->{$_.':maxTries'},
+ sprintf("%.2f", $data->{$_.':mean'}),
+ $data->{$_.':correct'},
+ $data->{$_.':correctByOverride'},
+ sprintf("%.1f", $data->{$_.':percentWrong'}),
+ sprintf("%.2f", $data->{$_.':degreeOfDifficulty'}),
+ sprintf("%.1f", $data->{$_.':standardDeviation'}),
+ sprintf("%.1f", $data->{$_.':skewness'}),
+ sprintf("%.2f", $data->{$_.':discriminationFactor1'}),
+ sprintf("%.2f", $data->{$_.':discriminationFactor2'}),
+ 0); # 0 is for discussion, need to figure out
+# $TempCache{'CacheTable:'.$_}=$join;
#6666666
# $r->print('<br>'.$out.'&'.$DoD);
@@ -557,26 +195,28 @@
#6666666
#check with Gerd
- $urlres=~/^(\w+)\/(\w+)/;
- if ($StdNo) {
- &Apache::lonnet::put('nohist_resevaldata',\%storestats,
- $1,$2);
- }
+# $urlres=~/^(\w+)\/(\w+)/;
+# if ($StdNo) {
+# &Apache::lonnet::put('nohist_resevaldata',\%storestats,
+# $1,$2);
+# }
#-------------------------------- Row of statistical table
- &TableRow($cache,$join,$cIdx,($p_count-1),$r,$color,
- \%TempCache);
- }
- $TempCache{'ProblemCount'}=$p_count;
- &CloseTable($cache,$r);
+ &TableRow($displayFormat,$tableData,$count,$r,$color);
+# $GraphDat->{'GraphGif:'.($count-1)}=$DoD.':'.$Wrng;
+ $count++;
}
-### &Close_PrgWin();
+# $TempCache{'ProblemCount'}=$count;
+ if($cache->{'DisplayFormat'} ne 'Display CSV Format') {
+ $r->print('</table>'."\n");
+ }
+ $r->print('</td></tr></table>');
#6666666
# close( OUT );
#666666
return \%TempCache;
}
-
+=pod
sub CacheStatisticsTable {
my ($state,$cache,$headings,$r,$color)=@_;
my @list = ();
@@ -608,10 +248,11 @@
if ($cIdx==$p_count) {
return \%TempCache;
}
- &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'},
+ $r->print(&CreateProblemStatisticsTableHeading(
+ $cache->{'DisplayFormat'},
$cache->{$sequence.':source'},
$cache->{$sequence.':title'},
- $headings,$r);
+ $headings,$r));
my ($tar)=split(/\&/,$list[$cIdx]);
$tar=~s/\+//eg;
@@ -629,10 +270,11 @@
}
}
else {
- &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'},
+ $r->print(&CreateProblemStatisticsTableHeading(
+ $cache->{'DisplayFormat'},
'Sorted by: ',
$headings->{$pos-1},
- $headings,$r);
+ $headings,$r));
for ( my $nIndex = 0; $nIndex < $p_count; $nIndex++ ) {
my($Pre, $Post) = split(/\+/,$list[$nIndex]);
&TableRow($cache,$Post,$nIndex,$nIndex,$r,$color,\%TempCache);
@@ -642,19 +284,18 @@
return \%TempCache;
}
-
+=cut
sub TableRow {
- my ($cache,$Str,$Idx,$RealIdx,$r,$color,$GraphDat)=@_;
- my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
+ my ($displayFormat,$Str,$RealIdx,$r,$color)=@_;
+ my($ref,$title,$source,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
$Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$DiscNo,$Prob)=split(/\&/,$Str);
my $Ptr;
- if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
- my ($ResId,$Dummy)=split(/\*/,$Prob);
+ if($displayFormat eq 'Display CSV Format') {
$Ptr="\n".'<br>'.
- "\n".'"'.($RealIdx+1).'",'.
- "\n".'"'.$cache->{$ResId.':title'}.$Dummy.'",'.
- "\n".'"'.$cache->{$ResId.':source'}.'",'.
+ "\n".'"'.$RealIdx.'",'.
+ "\n".'"'.$title.'",'.
+ "\n".'"'.$source.'",'.
"\n".'"'.$StdNo.'",'.
"\n".'"'.$TotalTries.'",'.
"\n".'"'.$MxTries.'",'.
@@ -672,8 +313,8 @@
$r->print("\n".$Ptr);
} else {
$Ptr="\n".'<tr>'.
- "\n".'<td>'.($RealIdx+1).'</td>'.
- "\n".'<td>'.$Temp.'</td>'.
+ "\n".'<td bgcolor="#ffffe6">'.$RealIdx.'</td>'.
+ "\n".'<td bgcolor="#ffffe6">'.$ref.'</td>'.
"\n".'<td bgcolor='.$color->{"yellow"}.'> '.$StdNo.'</td>'.
"\n".'<td bgcolor='.$color->{"yellow"}.'>'.$TotalTries.'</td>'.
"\n".'<td bgcolor='.$color->{"yellow"}.'>'.$MxTries.'</td>'.
@@ -689,9 +330,9 @@
"\n".'<td bgcolor='.$color->{"yellow"}.'> '.$DiscNo.'</td>';
$r->print("\n".$Ptr.'</tr>' );
}
- $GraphDat->{'GraphGif:'.$RealIdx}=$DoD.':'.$Wrng;
-}
+ return;
+}
# For loading the colored table for display or un-colored for print
sub setbgcolor {
@@ -740,16 +381,16 @@
$Ptr = '<table border="0">';
$Ptr .= '<tr><td>';
$Ptr .= '<b>#Stdnts</b></td>';
- $Ptr .= '<td>Total Number of Students opened the problem.';
+ $Ptr .= '<td>Total number of students attempted the problem.';
$Ptr .= '</td></tr><tr><td>';
$Ptr .= '<b>Tries</b></td>';
- $Ptr .= '<td>Total Number of Tries for solving the problem.';
+ $Ptr .= '<td>Total number of tries for solving the problem.';
$Ptr .= '</td></tr><tr><td>';
$Ptr .= '<b>Mod</b></td>';
- $Ptr .= '<td>Maximunm Number of Tries for solving the problem.';
+ $Ptr .= '<td>Largest number of tries for solving the problem by a student.';
$Ptr .= '</td></tr><tr><td>';
$Ptr .= '<b>Mean</b></td>';
- $Ptr .= '<td>Average Number of the tries. [ Tries / #Stdnts ]';
+ $Ptr .= '<td>Average number of tries. [ Tries / #Stdnts ]';
$Ptr .= '</td></tr><tr><td>';
$Ptr .= '<b>#YES</b></td>';
$Ptr .= '<td>Number of students solved the problem correctly.';
@@ -757,9 +398,9 @@
$Ptr .= '<b>#yes</b></td>';
$Ptr .= '<td>Number of students solved the problem by override.';
$Ptr .= '</td></tr><tr><td>';
- $Ptr .= '<b>%Wrng</b></td>';
- $Ptr .= '<td>Percentage of students tried to solve the problem ';
- $Ptr .= 'but still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
+ $Ptr .= '<b>%Wrong</b></td>';
+ $Ptr .= '<td>Percentage of students who tried to solve the problem ';
+ $Ptr .= 'but is still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
$Ptr .= '</td></tr><tr><td>';
$Ptr .= '<b>DoDiff</b></td>';
$Ptr .= '<td>Degree of Difficulty of the problem. ';
@@ -792,8 +433,184 @@
}
#------- Processing upperlist and lowerlist according to each problem
+
+sub ExtractStudentData {
+ my ($cache, $students)=@_;
+
+#$Apache::lonxml::debug=1;
+#&Apache::lonhomework::showhash(%$cache);
+#$Apache::lonxml::debug=0;
+
+ my @problemList=();
+ my %problemData;
+ foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
+ if($cache->{'ProblemStatisticsMaps'} ne 'All Maps' &&
+ $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
+ next;
+ }
+
+ foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
+ foreach my $part (split(/\:/,$cache->{$sequence.':'.
+ $problemID.
+ ':parts'})) {
+ my $id = $sequence.':'.$problemID.':'.$part;
+ push(@problemList, $id);
+ my $totalTries = 0;
+ my $totalAwarded = 0;
+ my $correct = 0;
+ my $correctByOverride = 0;
+ my $studentCount = 0;
+ my $maxTries = 0;
+ my $totalFirst = 0;
+ my @studentTries=();
+ foreach(@$students) {
+ my $code = $cache->{"$_:$problemID:$part:code"};
+
+ if(defined($cache->{$_.':error'}) || $code eq ' ' ||
+ $cache->{"$_:$problemID:NoVersion"} eq 'true') {
+ next;
+ }
+
+ $studentCount++;
+ my $tries = $cache->{"$_:$problemID:$part:tries"};
+ if($maxTries < $tries) {
+ $maxTries = $tries;
+ }
+ $totalTries += $tries;
+ push(@studentTries, $tries);
+
+ my $awarded = $cache->{"$_:$problemID:$part:awarded"};
+ $totalAwarded += $awarded;
+
+ if($code eq '*') {
+ $correct++;
+ if($tries == 1) {
+ $totalFirst++;
+ }
+ } elsif($code eq '+') {
+ $correctByOverride++;
+ }
+ }
+
+ $problemData{$id.':sequenceTitle'} =
+ $cache->{$sequence.':title'};
+ $problemData{$id.':studentCount'} = $studentCount;
+ $problemData{$id.':totalTries'} = $totalTries;
+ $problemData{$id.':studentTries'} = \@studentTries;
+ $problemData{$id.':totalAwarded'} = $totalAwarded;
+ $problemData{$id.':correct'} = $correct;
+ $problemData{$id.':correctByOverride'} = $correctByOverride;
+ $problemData{$id.':wrong'} = $studentCount -
+ ($correct + $correctByOverride);
+ $problemData{$id.':maxTries'} = $maxTries;
+ $problemData{$id.':totalFirst'} = $totalFirst;
+ }
+ }
+ }
+
+ $problemData{'problemList'} = \@problemList;
+# $Discussed=0;
+# if($Discuss->{"$name:$problem"}) {
+# $TotDiscuss++;
+# $Discussed=1;
+# }
+
+ return \%problemData;
+}
+
+sub SortProblems {
+ my ($problemData,$sortBy,$ascend)=@_;
+
+ if($sortBy eq "Homework Sets Order") {
+ return;
+ }
+
+ my $data;
+
+ if ($sortBy eq "#Stdnts") { $data = ':studentCount'; }
+ elsif($sortBy eq "Tries") { $data = ':totalTries'; }
+ elsif($sortBy eq "Mod") { $data = ':maxTries'; }
+ elsif($sortBy eq "Mean") { $data = ':mean'; }
+ elsif($sortBy eq "#YES") { $data = ':correct'; }
+ elsif($sortBy eq "#yes") { $data = ':correctByOverride'; }
+ elsif($sortBy eq "%Wrng") { $data = ':percentWrong'; }
+ elsif($sortBy eq "DoDiff") { $data = ':degreeOfDifficulty'; }
+ elsif($sortBy eq "S.D.") { $data = ':standardDeviation'; }
+ elsif($sortBy eq "Skew.") { $data = ':skewness'; }
+ elsif($sortBy eq "D.F.1st") { $data = ':discriminantFactor1'; }
+ elsif($sortBy eq "D.F.2nd") { $data = ':discriminantFactor2'; }
+ elsif($sortBy eq "Disc.") { $data = ''; }
+ else { return; }
+
+ my $problems = $problemData->{'problemList'};
+ my @orderedProblems =
+ sort { $problemData->{$a.$data} <=> $problemData->{$b.$data} }
+ @$problems;
+ if($ascend eq 'Descending') {
+ @orderedProblems = reverse(@orderedProblems);
+ }
+
+ $problemData->{'problemList'} = \@orderedProblems;
+
+ return;
+}
+
+sub CalculateStatistics {
+ my ($data)=@_;
+
+ my $problems = $data->{'problemList'};
+ foreach(@$problems) {
+ # Mean
+ $data->{$_.':mean'} = ($data->{$_.':studentCount'}) ?
+ ($data->{$_.':totalTries'} / $data->{$_.':studentCount'}) : 0;
+
+ # %Wrong
+ $data->{$_.':percentWrong'} = ($data->{$_.':studentCount'}) ?
+ (($data->{$_.':wrong'} / $data->{$_.':studentCount'}) * 100.0) :
+ 100.0;
+
+ # Degree of Difficulty
+ $data->{$_.':degreeOfDifficulty'} = ($data->{$_.':totalTries'}) ?
+ (1 - (($data->{$_.':correct'} + $data->{$_.':correctByOverride'}) /
+ $data->{$_.':totalTries'})) : 0;
+
+ # Factor in mean
+ my $studentTries = $data->{$_.':studentTries'};
+ foreach(my $index=0; $index < scalar(@$studentTries); $index++) {
+ $studentTries->[$index] -= $data->{$_.':mean'};
+ }
+ my $sumSquared = 0;
+ my $sumCubed = 0;
+ foreach(@$studentTries) {
+ my $squared = ($_ * $_);
+ my $cubed = ($squared * $_);
+ $sumSquared += $squared;
+ $sumCubed += $cubed;
+ }
+
+ # Standard deviation
+ $data->{$_.':standardDeviation'} = ($data->{$_.':studentCount'} - 1) ?
+ ((sqrt($sumSquared)) / ($data->{$_.':studentCount'} - 1)) : 0;
+
+ # Skewness
+ my $standardDeviation = $data->{$_.':standardDeviation'};
+ $data->{$_.':skewness'} = ($data->{$_.':standardDeviation'}) ?
+ (((sqrt($sumSquared)) / $data->{$_.':studentCount'}) /
+ ($standardDeviation * $standardDeviation * $standardDeviation)) :
+ 0;
+
+ # Discrimination Factor 1
+ $data->{$_.':discriminationFactor1'} = 0;
+
+ # Discrimination Factor 2
+ $data->{$_.':discriminationFactor2'} = 0;
+ }
+
+ return;
+}
+
sub ProcessDiscriminant {
- my ($List,$r) = @_;
+ my ($List) = @_;
my @sortedList = sort (@$List);
my $Count = scalar @sortedList;
my $Problem;
@@ -806,7 +623,7 @@
my $nStudent=0;
my %Proc=undef;
while ($nIndex<$Count) {
-# $r->print("<br> $nIndex) $sortedList[$nIndex]");
+# $jr->print("<br> $nIndex) $sortedList[$nIndex]");
($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
@Dis=split(/\+/,$tmp);
my $Temp = $Problem;
@@ -819,7 +636,7 @@
@Dis=split(/\+/,$tmp);
} while ( $Problem eq $Temp && $nIndex < $Count );
$Proc{$Temp}=($Sum1/$nStudent).':'.($Sum2/$nStudent);
-# $r->print("<br> $nIndex) $Temp --> ($nStudent) $Proc{$Temp}");
+# $jr->print("<br> $nIndex) $Temp --> ($nStudent) $Proc{$Temp}");
$Sum1=0;
$Sum2=0;
$nStudent=0;
@@ -830,7 +647,7 @@
#------- Creating Discimination factor
sub Discriminant {
- my ($discriminant,$r)=@_;
+ my ($discriminant)=@_;
my @discriminantKeys=keys(%$discriminant);
my $Count = scalar @discriminantKeys;
@@ -854,8 +671,8 @@
}
}
}
- my %DisUp = &ProcessDiscriminant(\@UpList,$r);
- my %DisLow = &ProcessDiscriminant(\@LowList,$r);
+ my %DisUp = &ProcessDiscriminant(\@UpList);
+ my %DisLow = &ProcessDiscriminant(\@LowList);
return (\%DisUp, \%DisLow);
}
Index: loncom/interface/statistics/lonstudentassessment.pm
diff -u loncom/interface/statistics/lonstudentassessment.pm:1.7 loncom/interface/statistics/lonstudentassessment.pm:1.8
--- loncom/interface/statistics/lonstudentassessment.pm:1.7 Mon Aug 5 16:53:38 2002
+++ loncom/interface/statistics/lonstudentassessment.pm Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonstudentassessment.pm,v 1.7 2002/08/05 20:53:38 stredwic Exp $
+# $Id: lonstudentassessment.pm,v 1.8 2002/08/13 00:37:18 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -104,35 +104,59 @@
my $selected=0;
$r->print('<pre>'."\n");
foreach (@$students) {
- if($c->aborted()) { return $Str; }
+ if($c->aborted()) { return $Str; }
next if ($_ ne $selectedName &&
$selectedName ne 'All Students');
$selected = 1;
- my $courseData;
- my $downloadTime='';
- if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
- $downloadTime = $cache{$_.':lastDownloadTime'};
- untie(%cache);
- }
- if($downloadTime eq 'Not downloaded') {
- $courseData =
- &Apache::loncoursedata::DownloadCourseInformation($_,
- $courseID);
- unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
- next;
- }
- &Apache::loncoursedata::ProcessStudentData(\%cache,
- $courseData, $_);
- untie(%cache);
- }
+ my @who = ($_);
+ next if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'true',
+ $cacheDB, 'true',
+ 'false', $courseID,
+ $r, $c) ne 'OK');
next if($c->aborted());
if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+ my @before=();
+ my @after=();
+ my @updateColumn=();
+ my $foundUpdate = 0;
+ foreach(@$infoKeys) {
+ if(/updateTime/) {
+ $foundUpdate=1;
+ push(@updateColumn, $_);
+ next;
+ }
+ if($foundUpdate) {
+ push(@after, $_);
+ } else {
+ push(@before, $_);
+ }
+ }
my $displayString = 'DISPLAYDATA'.$spacing;
$r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
\%cache, $_,
- $infoKeys,
+ \@before,
+ $displayString,
+ 'preformatted'));
+
+ if($foundUpdate) {
+ $displayString = '';
+ $displayString .= '<a href="/adm/statistics?reportSelected=';
+ $displayString .= &Apache::lonnet::escape('Student Assessment');
+ $displayString .= '&download='.$_.'">';
+ $displayString .= 'DISPLAYDATA</a>'.$spacing;
+ $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
+ \%cache, $_,
+ \@updateColumn,
+ $displayString,
+ 'preformatted'));
+ }
+
+ $displayString = 'DISPLAYDATA'.$spacing;
+ $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
+ \%cache, $_,
+ \@after,
$displayString,
'preformatted'));
$r->print(&StudentReport(\%cache, $_, $spacing, $sequenceKeys));
@@ -214,7 +238,7 @@
$displayString,
'preformatted');
- $displayString = '<td align="left"><pre>DISPLAYDATA'.$spacing;
+ $displayString = '<td align="left"><pre>DISPLAYDATAFORMATTING'.$spacing;
$displayString .= '</pre></td>'."\n";
$Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
$sequenceKeys,
@@ -265,109 +289,42 @@
my ($username,$domain)=split(':',$name);
my $Str = '';
+ if(defined($cache->{$name.':error'})) {
+ return $Str;
+ }
if($cache->{$name.':error'} =~ /course/) {
$Str .= '<b><font color="blue">No course data for student </font>';
$Str .= '<font color="red">'.$username.'.</font></b><br>';
return $Str;
}
- my $Version;
- my $problemsCorrect = 0;
- my $totalProblems = 0;
- my $problemsSolved = 0;
- my $numberOfParts = 0;
-# foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
foreach my $sequence (@$showSequences) {
my $characterCount=0;
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'})) {
- $Str .= ' ';
- $totalProblems++;
- $characterCount++;
- }
- 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=' ';
-
- $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 = '*';}
- elsif ($val eq 'correct_by_override') {$code = '+';}
- elsif ($val eq 'incorrect_attempted') {$code = '.';}
- elsif ($val eq 'incorrect_by_override'){$code = '-';}
- elsif ($val eq 'excused') {$code = 'x';}
- elsif ($val eq 'ungraded_attempted') {$code = '#';}
- else {$code = ' ';}
- $partData{$part.':code'}=$code;
- }
- }
-
# 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
- $Str .= '<a href="/adm/grades?symb=';
- $Str .= &Apache::lonnet::escape($problem);
- $Str .= '&student='.$username.'&domain='.$domain;
- $Str .= '&command=submission">';
foreach(split(/\:/,$cache->{$sequence.':'.$problemID.
':parts'})) {
- if($partData{$_.':code'} eq '*') {
- $problemsCorrect++;
- if (($partData{$_.':tries'}<10) &&
- ($partData{$_.':tries'} ne '')) {
- $partData{$_.':code'}=$partData{$_.':tries'};
- }
- } elsif($partData{$_.':code'} eq '+') {
- $problemsCorrect++;
- }
-
- $Str .= $partData{$_.':code'};
$characterCount++;
-
- if($partData{$_.':code'} ne 'x') {
- $totalProblems++;
+ if(defined($cache->{$name.':'.$problemID.':NoVersion'}) ||
+ $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ') {
+ $Str .= ' ';
+ next;
}
+ $Str .= '<a href="/adm/grades?symb=';
+ $Str .= &Apache::lonnet::escape($problem);
+ $Str .= '&student='.$username.'&domain='.$domain;
+ $Str .= '&command=submission">';
+ my $code = $cache->{$name.':'.$problemID.':'.$_.':code'};
+ my $tries = $cache->{$name.':'.$problemID.':'.$_.':tries'};
+ if($code eq '*' && $tries < 10 && $tries ne '') {
+ $code = $tries;
+ }
+ $Str .= $code;
+ $Str.='</a>';
}
- $Str.='</a>';
}
# Output the number of correct answers for the current sequence.
@@ -377,19 +334,17 @@
$spacesNeeded -= 3;
$Str .= (' 'x$spacesNeeded);
- my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
+ my $outputProblemsCorrect = sprintf("%3d", $cache->{$name.':'.$sequence.
+ ':problemsCorrect'});
$Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
- $problemsSolved += $problemsCorrect;
- $problemsCorrect=0;
-
$Str .= $spacing;
}
# 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", $problemsSolved );
- my $outputTotalProblems = sprintf( "%4d", $totalProblems );
+ my $outputProblemsSolved = sprintf("%4d", $cache->{$name.':problemsSolved'});
+ my $outputTotalProblems = sprintf("%4d", $cache->{$name.':totalProblems'});
$Str .= '<font color="#000088">'.$outputProblemsSolved.
' / '.$outputTotalProblems.'</font>';
--stredwic1029199038--