#!/usr/bin/perl
## This file is profCourseRecData.pl
## It displays overall data on how students in various recitations
## are doing on problems. E.g. the instructor can spot difficult
## problems.
##
####################################################################
# Copyright @ 1995-1998 University of Rochester
# All Rights Reserved
####################################################################
use lib '/ww/webwork/development/'; # mainWeBWorKDirectory;
use strict;
use Global;
use Auth;
use CGI qw(:standard);
# Timing code
use Benchmark;
my $beginTime = new Benchmark;
# end Timing code
my %inputs;
my ($classID, $setNumber,$User,$Session_key,$batchMode);
&CGI::ReadParse;
%inputs = %main::in;
# get information from CGI inputs (see also below for additional information)
$classID = $inputs{'course'};
$setNumber = $inputs{'setNo'};
$User = $inputs{'user'};
$Session_key = $inputs{'key'};
unless ($classID && $User && $Session_key) {
&wwerror("$0","The script profCourseRecData.pl did not receive the proper input data.","","", query_string());
}
# CAUTION: FOR THIS SCRIPT TO WORK CORRECTLTY, ALL STUDENTS
# MUST HAVE BEEN ASSIGNED THE SAME NUMBER OF PROBLREMS
# print "set is $setNumber";
# print "classID is $classID";
&getCourseEnvironment($classID);
my $scriptDirectory = getWebworkScriptDirectory;
my $databaseDirectory = getCourseDatabaseDirectory;
my $templateDirectory = getCourseTemplateDirectory;
my $cgiURL = getWebworkCgiURL;
require "${scriptDirectory}$Global::DBglue_pl";
require "${scriptDirectory}$Global::FILE_pl";
require "${scriptDirectory}$Global::SCRtools_pl";
require "${scriptDirectory}$Global::HTMLglue_pl";
my $keyFile = &Global::getCourseKeyFile($classID);
&verify_key($User, $Session_key, $keyFile, $classID);
my $permissionsFile = &Global::getCoursePermissionsFile($classID);
my $permissions = &get_permissions($User, $permissionsFile);
if (($permissions != $Global::instructor_permissions) and ($permissions != $Global::TA_permissions) ) {
print "permissions = $permissions instructor_permissions= $Global::instructor_permissions\n";
print &html_NO_PERMISSION;
exit(0);
}
my $DELIM = $Global::delim;
## get rest of data from cgi form
$batchMode = $inputs{'batchMode'}; ## if 1 it means user has choosen to ignore warning message
# get list of problems and values from the database. Warn user if different students
#have different numbers of problems or different valuse for the same problem
my $cgiMode = 1;
my ($warningMsg,$dueDate, $problemListref,$problemValueListref)
= &readProblemsAndValuesFromDB($setNumber,0,$cgiMode,$batchMode);
if ($warningMsg ne '') { &warningMsgPage(\%inputs,$warningMsg);}
my @problemList = @$problemListref;
my @problemValueList = @$problemValueListref;
my $noOfProbs = @problemList;
unshift @problemValueList, 0; ##off by 1 problem
my (%NHash,%YHash,%attemptedProbHash);
my (%totalScoreHash,%attemptedSetHash,%allStudentsHash);
my $total_possible;
my @recitationNameArray = &getAllClassRecitations($setNumber) ;
my @excludedRecitationNameArray = ();
@excludedRecitationNameArray = @Global::excluse_these_recitations_from_overall_statistics
if defined @Global::excluse_these_recitations_from_overall_statistics;
&processRecitationNameArrays(); ##separate included and excluded Recitations
## initialize hashes and load up data
my $all = &uniqueCourseName();
&initializeAndLoadUp(\@recitationNameArray,$all);
# begin printing HTML text
print &htmlTOP("WeBWorK Course Data");
# print navigation buttons
print qq!
!;
print <
The first two tables do not contain data from "excluded" recitations. Excluded recitations
typically contain practices uses, T.A.'s, prof's etc. Data for excluded recitations is displayed
at the bottom of the page.
EOF
## create $dat arrays with the info. on average scores, etc
my ($recitationName,$i, $dataRow,$item);
my @dataArray =();
## first row
$dataRow = "recitations$DELIM \# of students$DELIM \% attempting set $setNumber$DELIM average score$DELIM possible score";
push @dataArray, $dataRow;
## display whole course data
$dataRow = "$all $DELIM $allStudentsHash{$all} $DELIM"; ## all Recitations and total # of students
$item =0; ## % of students who have attempted at least one problem in set
$item = int(100*$attemptedSetHash{$all}/$allStudentsHash{$all}+.5) if $allStudentsHash{$all};
$dataRow .= "$item $DELIM";
$item =0; ## avg score of students who have attempted at least one problem in set
$item = (int($totalScoreHash{$all} *10/$attemptedSetHash{$all}+.5))/10 if $attemptedSetHash{$all};
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
$dataRow .= "$total_possible";
push @dataArray, $dataRow;
## display data for Recitations
foreach $recitationName (@recitationNameArray) {
$dataRow = "$recitationName $DELIM $allStudentsHash{$recitationName} $DELIM"; ## all recitations and total # of students
$item =0; ## % of students who have attempted at least one problem in set
$item = int(100*$attemptedSetHash{$recitationName}/$allStudentsHash{$recitationName}+.5) if $allStudentsHash{$recitationName};
$dataRow .= "$item $DELIM";
$item =0; ## avg score of students who have attempted at least one problem in set
$item = (int($totalScoreHash{$recitationName} *10/$attemptedSetHash{$recitationName}+.5))/10 if $attemptedSetHash{$recitationName};
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
$dataRow .= "$total_possible";
push @dataArray, $dataRow;
}
# print "
EOF
&initializeAndLoadUp(\@excludedRecitationNameArray,'Excluded');
$all = 'Excluded';
## create $dat arrays with the info. on average scores, etc
@dataArray =();
## first row
$dataRow = "recitations$DELIM \# of students$DELIM \% attempting set $setNumber$DELIM average score$DELIM possible score";
push @dataArray, $dataRow;
## display whole course data
$dataRow = "$all $DELIM $allStudentsHash{$all} $DELIM"; ## all recitations and total # of students
$item =0; ## % of students who have attempted at least one problem in set
$item = int(100*$attemptedSetHash{$all}/$allStudentsHash{$all}+.5) if $allStudentsHash{$all};
$dataRow .= "$item $DELIM";
$item =0; ## avg score of students who have attempted at least one problem in set
$item = (int($totalScoreHash{$all} *10/$attemptedSetHash{$all}+.5))/10 if $attemptedSetHash{$all};
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
$dataRow .= "$total_possible";
push @dataArray, $dataRow;
## display data for recitations
foreach $recitationName (@excludedRecitationNameArray) {
$dataRow = "$recitationName $DELIM $allStudentsHash{$recitationName} $DELIM"; ## all recitations and total # of students
$item =0; ## % of students who have attempted at least one problem in set
$item = int(100*$attemptedSetHash{$recitationName}/$allStudentsHash{$recitationName}+.5) if $allStudentsHash{$recitationName};
$dataRow .= "$item $DELIM";
$item =0; ## avg score of students who have attempted at least one problem in set
$item = (int($totalScoreHash{$recitationName} *10/$attemptedSetHash{$recitationName}+.5))/10 if $attemptedSetHash{$recitationName};
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
$dataRow .= "$total_possible";
push @dataArray, $dataRow;
}
# print "
!;
print <
Current Statistics for set $setNumber in $classID
On this page, you can monitor the average progress of students for all recitations or
by individual recitations. You can identify difficult problems by the percentage of students
who have answered the problem correctly and/or by the average number of incorrect attempts
per problem. All percentages and averages (except \% attempting) are based on the number of
students who have attempted a set or problem, not on the total number of students in the recitation
or course. Note that 50\% correct on a partial credit question could mean all students got half
credit or half the students got full credit and half got no credit. @dataArray <\pre>";
print <
Overall Scores by recitation. $all is the total for all included recitations
EOF
## output the html table
my $string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
print "${string}
";
## now output the info on individaul problems
### display whole course data
@dataArray =();
$dataRow = "$all $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$dataRow .= "\# $i $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "\% attempting $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## percent of students who have attempted this problem
$item = int(100*$attemptedProbHash{$all}[$i]/$allStudentsHash{$all}+.5) if $allStudentsHash{$all};
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "percent correct $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## % of students who have attempted this problem
$item = int(100*$YHash{$all}[$i]/$attemptedProbHash{$all}[$i]+.5) if $attemptedProbHash{$all}[$i];
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "average incorrect $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## avg # of incorrect attempts of students who have attempted this problem
$item = (int(10*$NHash{$all}[$i]/$attemptedProbHash{$all}[$i]+.5))/10 if $attemptedProbHash{$all}[$i];
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
print <
";
## display data for recitations
foreach $recitationName (@recitationNameArray) {
## add blank row to table to seperate recitations
$dataRow = '
';
push @dataArray, $dataRow;
# @dataArray =();
$dataRow = "$recitationName $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$dataRow .= "\# $i $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "\% attempting $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## percent of students who have attempted this problem
$item = int(100*$attemptedProbHash{$recitationName}[$i]/$allStudentsHash{$recitationName}+.5) if $allStudentsHash{$recitationName};
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "percent correct $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## % of students who have attempted this problem
$item = int(100*$YHash{$recitationName}[$i]/$attemptedProbHash{$recitationName}[$i]+.5) if $attemptedProbHash{$recitationName}[$i];
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "average incorrect $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## avg # of incorrect attempts of students who have attempted this problem
$item = (int(10*$NHash{$recitationName}[$i]/$attemptedProbHash{$recitationName}[$i]+.5))/10 if $attemptedProbHash{$recitationName}[$i];
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
# ## output the html table
# my $string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
# print "${string}
";
}
## output the html table
$string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
print "${string}
";
## Now print everything again for excluded recitations
##################################################################################################
print <
Current Statistics for Excluded Recitations
Excluded recitations typically contain practices uses, T.A.'s, prof's etc. The list
of excluded recitations in contained in the webworkCourse.ph file and typically consists
of a recitation with an empty name.
@dataArray <\pre>";
print <
Overall Scores by recitation. $all is the total for all excluded recitations
EOF
## output the html table
$string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
print "${string}
";
## now output the info on individaul problems
### display whole course data
@dataArray =();
$dataRow = "$all $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$dataRow .= "\# $i $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "\% attempting $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## percent of students who have attempted this problem
$item = int(100*$attemptedProbHash{$all}[$i]/$allStudentsHash{$all}+.5) if $allStudentsHash{$all};
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "percent correct $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## % of students who have attempted this problem
$item = int(100*$YHash{$all}[$i]/$attemptedProbHash{$all}[$i]+.5) if $attemptedProbHash{$all}[$i];
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "average incorrect $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## avg # of incorrect attempts of students who have attempted this problem
$item = (int(10*$NHash{$all}[$i]/$attemptedProbHash{$all}[$i]+.5))/10 if $attemptedProbHash{$all}[$i];
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
print <
";
## display data for recitations
foreach $recitationName (@excludedRecitationNameArray) {
## add blank row to table to seperate recitations
$dataRow = '
';
push @dataArray, $dataRow;
# @dataArray =();
$dataRow = "$recitationName $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$dataRow .= "\# $i $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "\% attempting $DELIM";
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## percent of students who have attempted this problem
$item = int(100*$attemptedProbHash{$recitationName}[$i]/$allStudentsHash{$recitationName}+.5) if $allStudentsHash{$recitationName};
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "percent correct $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## % of students who have attempted this problem
$item = int(100*$YHash{$recitationName}[$i]/$attemptedProbHash{$recitationName}[$i]+.5) if $attemptedProbHash{$recitationName}[$i];
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
$dataRow = "average incorrect $DELIM"; ## all recitations and total # of students
for ($i=1;$i<=$noOfProbs;$i++) {
$item =0; ## avg # of incorrect attempts of students who have attempted this problem
$item = (int(10*$NHash{$recitationName}[$i]/$attemptedProbHash{$recitationName}[$i]+.5))/10 if $attemptedProbHash{$recitationName}[$i];
$item = sprintf '%.1f', $item;
$dataRow .= "$item $DELIM";
}
$dataRow =~ s|$DELIM$||; ## remove last \$DELIM
push @dataArray, $dataRow;
# ## output the html table
# my $string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
# print "${string}
";
}
## output the html table
$string = &delimitedArray2htmlTable(\@dataArray, 'htmltable');
print "${string}
";
####################################################################################################
print &htmlBOTTOM("profCourseRecData.pl", \%inputs, 'profCourseRecDataHelp.html');
# begin Timing code
my $endTime = new Benchmark;
&Global::logTimingInfo($beginTime,$endTime,"profCourseRecData.pl",$inputs{'course'},$inputs{'user'});
# end Timing code
exit;
##subroutines
sub processRecitationNameArrays {
## first consider all blank entries (i.e. empty or white space) in excludedRecitationNameArray
## to be the same recitation, namely ' '
my %temp_hash =();
my $recitationName;
foreach $recitationName (@excludedRecitationNameArray) {
if ((!defined ($recitationName)) or ($recitationName =~ m|^\s*$|)) {$recitationName = ' ';}
$temp_hash{$recitationName} =1;
}
@excludedRecitationNameArray = keys %temp_hash;
## Make sure excludedRecitationNameArray is a subset of recitationNameArray
%temp_hash =();
grep($temp_hash{$_}++,@recitationNameArray);
@excludedRecitationNameArray = grep($temp_hash{$_},@excludedRecitationNameArray);
## Now remove excluded recitations from recitation list
%temp_hash =();
grep($temp_hash{$_}++,@excludedRecitationNameArray);
@recitationNameArray = grep(!$temp_hash{$_},@recitationNameArray);
@recitationNameArray = sort @recitationNameArray;
@excludedRecitationNameArray = sort @excludedRecitationNameArray;
}
sub initializeAndLoadUp {
my ($recitationNameArrayref, $wholeCourseName) = @_;
my @recitationNameArray = @$recitationNameArrayref;
my $all = $wholeCourseName;
my ($recitationName,$i,$score);
## compute total possible points
$total_possible = 0;
for ($i=1;$i<=$noOfProbs;$i++) {$total_possible += $problemValueList[$i];}
foreach $recitationName (@recitationNameArray) {
$totalScoreHash{$recitationName} = 0;
$attemptedSetHash{$recitationName} = 0;
$allStudentsHash{$recitationName} = 0;
for ($i=1;$i<=$noOfProbs;$i++) {
$NHash{$recitationName}[$i]=0; ## contains number of incorrect responses
$YHash{$recitationName}[$i]=0; ## contains totals of problem scores (i.e. a
## number in [0,1] for each problem
$attemptedProbHash{$recitationName}[$i]=0;
}
}
## load up hashes with data
my @pinNumbersArray = &getAllProbSetKeysForSet($setNumber);
my ($studentAttemptedAProblem, $numIncorr, $pin, $status);
foreach $pin (@pinNumbersArray) {
&attachProbSetRecord($pin);
$status = getStudentStatus($pin);
next if dropStatus($status);
$studentAttemptedAProblem = 0;
$recitationName = &getClassRecitation($pin);
if ((!defined ($recitationName)) or ($recitationName =~ m|^\s*$|)){
$recitationName = ' ';
}
$allStudentsHash{$recitationName} += 1;
for ($i=1;$i<=$noOfProbs;$i++) {
if (&getProblemAttempted($i,$pin)) {
$studentAttemptedAProblem = 1;
$numIncorr = &getProblemNumOfIncorrectAns($i,$pin);
$numIncorr =0 unless defined $numIncorr;
$numIncorr = &min($numIncorr,99);
$NHash{$recitationName}[$i] += $numIncorr;
$attemptedProbHash{$recitationName}[$i] += 1;
$score = &getProblemStatus($i,$pin);
$YHash{$recitationName}[$i] += $score;
$totalScoreHash{$recitationName} += round_score($score*$problemValueList[$i]);
}
}
if ($studentAttemptedAProblem) {$attemptedSetHash{$recitationName} += 1;}
}
## initialize whole course data
$totalScoreHash{$all} = 0;
$attemptedSetHash{$all} = 0;
$allStudentsHash{$all} = 0;
for ($i=1;$i<=$noOfProbs;$i++) {
$NHash{$all}[$i]=0;
$YHash{$all}[$i]=0;
$attemptedProbHash{$all}[$i]=0;
}
## compute whole course data
foreach $recitationName (@recitationNameArray) {
$totalScoreHash{$all} += $totalScoreHash{$recitationName};
$attemptedSetHash{$all} += $attemptedSetHash{$recitationName};
$allStudentsHash{$all} += $allStudentsHash{$recitationName};
for ($i=1;$i<=$noOfProbs;$i++) {
$NHash{$all}[$i] += $NHash{$recitationName}[$i];
$YHash{$all}[$i] += $YHash{$recitationName}[$i];
$attemptedProbHash{$all}[$i] += $attemptedProbHash{$recitationName}[$i];
}
}
}
## find unique name
sub uniqueCourseName {
my $all = $classID;
if (exists $allStudentsHash{$all}) {
my $j = 1;
$all = "${all}$j";
while (exists $allStudentsHash{$all}) {
$j++;
$all = "${all}$j";
}
}
$all
}
sub warningMsgPage {
my ($inputref,$warningMsg) = @_;
my %inputs = %$inputref;
# print HTML text
print &htmlTOP("Scoring Utilities");
# print navigation buttons
print qq!
WeBWorK scoring WARNING message for $classID:
EOF
print "";
print $warningMsg;
print "
";
print "To Continue displaying data for $setNumber, check the \"Continue\" check box and then select
\"Continue displaying data for $setNumber\".
To Quit and return to the Scoring page, select the \"Up\"
buttom.";
## profScoring form -- allows you to score problem sets
print <