[LON-CAPA-cvs] cvs: loncom /interface lonmeta.pm /interface/statistics lonproblemstatistics.pm /metadata_database/LONCAPA lonmetadata.pm

matthew lon-capa-cvs@mail.lon-capa.org
Fri, 16 Apr 2004 21:43:56 -0000


This is a MIME encoded message

--matthew1082151836
Content-Type: text/plain

matthew		Fri Apr 16 17:43:56 2004 EDT

  Modified files:              
    /loncom/metadata_database/LONCAPA	lonmetadata.pm 
    /loncom/interface	lonmeta.pm 
    /loncom/interface/statistics	lonproblemstatistics.pm 
  Log:
  lonmeta.pm: Added degree of discrimination output.
  Added 'detailed assessment statistical data' output, a table of classes,
  sections, and various statistics which make up the 'overall assessment
  statistical data'.  
  lonmetadata.pm: Documented data storage in nohist_resevaldata.db
  &process_dynmaic_metadata now uses a weighted average for statistics, and
  reports the sum of the maximum number of students per class as 'stdno',
  since there may be multiple entries per class.
  Added &dynamic_metadata_storage which prepares statistical data for
  storage in nohist_resevaldata.db.
  lonproblemstatistics.pm: Use lonmetadata::dynamic_metadata_storage to prepare
  storage of dynamic metadata.
  
  
--matthew1082151836
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20040416174356.txt"

Index: loncom/metadata_database/LONCAPA/lonmetadata.pm
diff -u loncom/metadata_database/LONCAPA/lonmetadata.pm:1.7 loncom/metadata_database/LONCAPA/lonmetadata.pm:1.8
--- loncom/metadata_database/LONCAPA/lonmetadata.pm:1.7	Wed Apr 14 16:35:29 2004
+++ loncom/metadata_database/LONCAPA/lonmetadata.pm	Fri Apr 16 17:43:56 2004
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonmetadata.pm,v 1.7 2004/04/14 20:35:29 matthew Exp $
+# $Id: lonmetadata.pm,v 1.8 2004/04/16 21:43:56 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -410,6 +410,48 @@
 
 =pod
 
+=item nohist_resevaldata.db data structure
+
+The nohist_resevaldata.db file has the following possible keys:
+
+ Statistics Data (values are integers, perl times, or real numbers)
+ ------------------------------------------
+ $course___$resource___avetries
+ $course___$resource___count
+ $course___$resource___difficulty
+ $course___$resource___stdno
+ $course___$resource___timestamp
+
+ Evaluation Data (values are on a 1 to 5 scale)
+ ------------------------------------------
+ $username@$dom___$resource___clear
+ $username@$dom___$resource___comments
+ $username@$dom___$resource___depth
+ $username@$dom___$resource___technical
+ $username@$dom___$resource___helpful
+
+ Course Context Data
+ ------------------------------------------
+ $course___$resource___course       course id
+ $course___$resource___comefrom     resource preceeding this resource
+ $course___$resource___goto         resource following this resource
+ $course___$resource___usage        resource containing this resource
+
+ New statistical data storage
+ ------------------------------------------
+ $course&$sec&$numstud___$resource___stats
+    $sec is a string describing the sections: all, 1 2, 1 2 3,...
+    Value is a '&' deliminated list of key=value pairs.
+    Possible keys are (currently) disc,course,sections,difficulty, 
+    stdno, timestamp
+
+=cut
+
+######################################################################
+######################################################################
+
+=pod
+
 =item &process_reseval_data 
 
 Process a nohist_resevaldata hash into a more complex data structure.
@@ -474,13 +516,15 @@
             # $source is $cid\_$sec\_$stdno
             # $value is stat1=value&stat2=value&stat3=value,....
             #
-            my ($cid,$sec,$stdno)=split('_',$source);
-            my $crssec = $cid.'_'.$sec;
+            my ($cid,$sec,$stdno)=split('&',$source);
+            my $crssec = $cid.'&'.$sec;
             my @Data = split('&',$value);
             my %Statistics;
             while (my ($key,$value) = split('=',pop(@Data))) {
                 $Statistics{$key} = $value;
             }
+            $sec =~ s:("$|^")::g;
+            $Statistics{'sections'} = $sec;
             #
             # Only store the data if the number of students is greater
             # than the data already stored
@@ -522,26 +566,71 @@
     my %data;
     my $resdata = $DynamicData->{$url};
     #
-    # Get the statistical data
-    foreach my $type (qw/avetries difficulty stdno/) {
-        my $count;
+    # Get the statistical data - Use a weighted average
+    foreach my $type (qw/avetries difficulty disc/) {
+        my $studentcount;
         my $sum;
         my @Values;
+        my @Students;
         #
+        # Old data
         foreach my $coursedata (values(%{$resdata->{'statistics'}}),
                                 values(%{$resdata->{'stats'}})) {
             if (ref($coursedata) eq 'HASH' && exists($coursedata->{$type})) {
-                $count++;
-                $sum += $coursedata->{$type};
+                $studentcount += $coursedata->{'stdno'};
+                $sum += ($coursedata->{$type}*$coursedata->{'stdno'});
                 push(@Values,$coursedata->{$type});
+                push(@Students,$coursedata->{'stdno'});
             }
         }
-        if ($count) {
-            $data{$type} = $sum/$count;
+        if (exists($resdata->{'stats'})) {
+            foreach my $identifier (sort(keys(%{$resdata->{'stats'}}))) {
+                my $coursedata = $resdata->{'stats'}->{$identifier};
+                $studentcount += $coursedata->{'stdno'};
+                $sum += $coursedata->{$type}*$coursedata->{'stdno'};
+                push(@Values,$coursedata->{$type});                
+                push(@Students,$coursedata->{'stdno'});
+            }
+        }
+        #
+        # New data
+        if (defined($studentcount) && $studentcount>0) {
+            $data{$type} = $sum/$studentcount;
             $data{$type.'_list'} = join(',',@Values);
         }
     }
     #
+    # Find out the number of students who have completed the resource...
+    my $stdno;
+    foreach my $coursedata (values(%{$resdata->{'statistics'}}),
+                            values(%{$resdata->{'stats'}})) {
+        if (ref($coursedata) eq 'HASH' && exists($coursedata->{'stdno'})) {
+            $stdno += $coursedata->{'stdno'};
+        }
+    }
+    if (exists($resdata->{'stats'})) {
+        #
+        # For the number of students, take the maximum found for the class
+        my $current_course;
+        my $coursemax=0;
+        foreach my $identifier (sort(keys(%{$resdata->{'stats'}}))) {
+            my $coursedata = $resdata->{'stats'}->{$identifier};
+            if (! defined($current_course)) {
+                $current_course = $coursedata->{'course'};
+            }
+            if ($current_course ne $coursedata->{'course'}) {
+                $stdno += $coursemax;
+                $coursemax = 0;
+                $current_course = $coursedata->{'course'};                
+            }
+            if ($coursemax < $coursedata->{'stdno'}) {
+                $coursemax = $coursedata->{'stdno'};
+            }
+        }
+        $stdno += $coursemax; # pick up the final course in the list
+    }
+    $data{'stdno'}=$stdno;
+    #
     # Get the context data
     foreach my $type (qw/course goto comefrom/) {
         if (defined($resdata->{$type}) && 
@@ -581,9 +670,33 @@
     $comments .= '</div>';
     $data{'comments'} = $comments;
     #
+    if (exists($resdata->{'stats'})) {
+        $data{'stats'} = $resdata->{'stats'};
+    }
+    #
     return %data;
 }
 
+sub dynamic_metadata_storage {
+    my ($data) = @_;
+    my %Store;
+    my $courseid = $data->{'course'};
+    my $sections = $data->{'sections'};
+    my $numstu = $data->{'num_students'};
+    my $urlres = $data->{'urlres'};
+    my $key = $courseid.'&'.$sections.'&'.$numstu.'___'.$urlres.'___stats';
+    $Store{$key} =
+        'course='.$courseid.'&'.
+        'sections='.$sections.'&'.
+        'timestamp='.time.'&'.
+        'stdno='.$data->{'num_students'}.'&'.
+        'avetries='.$data->{'mean_tries'}.'&'.
+        'difficulty='.$data->{'deg_of_diff'};
+    if (exists($data->{'deg_of_disc'})) {
+        $Store{$key} .= '&'.'disc='.$data->{'deg_of_disc'};
+    }
+    return %Store;
+}
 
 ######################################################################
 ######################################################################
Index: loncom/interface/lonmeta.pm
diff -u loncom/interface/lonmeta.pm:1.72 loncom/interface/lonmeta.pm:1.73
--- loncom/interface/lonmeta.pm:1.72	Thu Apr 15 14:06:29 2004
+++ loncom/interface/lonmeta.pm	Fri Apr 16 17:43:56 2004
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Metadata display handler
 #
-# $Id: lonmeta.pm,v 1.72 2004/04/15 18:06:29 matthew Exp $
+# $Id: lonmeta.pm,v 1.73 2004/04/16 21:43:56 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -193,7 +193,8 @@
          'technical'  => 'Resource is technically correct', 
          'avetries'   => 'Average number of tries till solved',
          'stdno'      => 'Total number of students who have worked on this problem',
-         'difficulty' => 'Degree of difficulty'
+         'difficulty' => 'Degree of difficulty',
+         'disc'       => 'Degree of discrimination',
          );
 }
 
@@ -283,7 +284,7 @@
 	return &evalgraph($value);
     }
     # Difficulty
-    if ($type eq 'difficulty') {
+    if ($type eq 'difficulty' || $type eq 'disc') {
 	return &diffgraph($value);
     }
     # List of courses
@@ -589,6 +590,8 @@
     $r->rflush();
     my %items=&fieldnames();
     my %dynmeta=&dynamicmeta($uri);
+    &Apache::lonnet::logthis('dynamic metadata keys:'.$/.
+                             join("\n",keys(%dynmeta)));
     #
     # General Access and Usage Statistics
     if (exists($dynmeta{'count'}) ||
@@ -613,23 +616,88 @@
     }
     #
     # Assessment statistics
-    if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/ &&
-        (exists($dynmeta{'stdno'}) ||
-         exists($dynmeta{'avetries'}) ||
-         exists($dynmeta{'difficulty'}))) {
-        # This is an assessment, print assessment data
-        $r->print('<h4>'.&mt('Assessment Statistical Data').'</h4>'.
-                  '<table cellspacing=2 border=0>');
-        foreach ('stdno','avetries','difficulty') {
-            $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'.
+    if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/) {
+        if (exists($dynmeta{'stdno'}) ||
+            exists($dynmeta{'avetries'}) ||
+            exists($dynmeta{'difficulty'}) ||
+            exists($dynmeta{'disc'})) {
+            # This is an assessment, print assessment data
+            $r->print('<h4>'.
+                      &mt('Overall Assessment Statistical Data').
+                      '</h4>'.
+                      '<table cellspacing=2 border=0>');
+            $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{'stdno'}.'</td>'.
                       '<td bgcolor="#CCCCCC">'.
-                      &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})).'</td>'.
-                      "</tr>\n");
+                      &prettyprint('stdno',$dynmeta{'stdno'}).
+                      '</td>'."</tr>\n");
+            foreach ('avetries','difficulty','disc') {
+                $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'.
+                          '<td bgcolor="#CCCCCC">'.
+                          &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})).
+                          '</td>'."</tr>\n");
+            }
+            $r->print('</table>');    
+        }
+        if (exists($dynmeta{'stats'})) {
+            #
+            # New assessment statistics
+            $r->print('<h4>'.
+                      &mt('Detailed Assessment Statistical Data').
+                      '</h4>');
+            my $table = '<table cellspacing=2 border=0>'.
+                '<tr>'.
+                '<th>Course</th>'.
+                '<th>Section(s)</th>'.
+                '<th>Num Students</th>'.
+                '<th>Mean Tries</th>'.
+                '<th>Degree of Difficulty</th>'.
+                '<th>Degree of Discrimination</th>'.
+                '<th>Time of computation</th>'.
+                '</tr>'.$/;
+            foreach my $identifier (sort(keys(%{$dynmeta{'stats'}}))) {
+                my $data = $dynmeta{'stats'}->{$identifier};
+                my $course = $data->{'course'};
+                my %courseinfo = &Apache::lonnet::coursedescription($course);
+                if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') {
+                    &Apache::lonnet::logthis('lookup for '.$course.' failed');
+                    next;
+                }
+                $table .= '<tr>';
+                $table .= 
+                    '<td><nobr>'.$courseinfo{'description'}.'</nobr></td>';
+                $table .= 
+                    '<td align="right">'.$data->{'sections'}.'</td>';
+                $table .=
+                    '<td align="right">'.$data->{'stdno'}.'</td>';
+                foreach ('avetries','difficulty','disc') {
+                    $table .= '<td align="right">';
+                    if (exists($data->{$_})) {
+                        $table .= sprintf('%.2f',$data->{$_}).'&nbsp;';
+                    } else {
+                        $table .= '';
+                    }
+                    $table .= '</td>';
+                }
+                $table .=
+                    '<td><nobr>'.
+                    &Apache::lonlocal::locallocaltime($data->{'timestamp'}).
+                    '</nobr></td>';
+                $table .=
+                    '</tr>'.$/;
+            }
+            $table .= '</table>'.$/;
+            $r->print($table);
+        } else {
+            $r->print('No new dynamic data found.');
         }
-        $r->print('</table>');    
     } else {
-        $r->print('<h4>'.&mt('No Assessment Statistical Data is available for this resource').'</h4>');
+        $r->print('<h4>'.
+          &mt('No Assessment Statistical Data is available for this resource').
+                  '</h4>');
     }
+
+    #
+    #
     if (exists($dynmeta{'clear'})   || 
         exists($dynmeta{'depth'})   || 
         exists($dynmeta{'helpful'}) || 
Index: loncom/interface/statistics/lonproblemstatistics.pm
diff -u loncom/interface/statistics/lonproblemstatistics.pm:1.83 loncom/interface/statistics/lonproblemstatistics.pm:1.84
--- loncom/interface/statistics/lonproblemstatistics.pm:1.83	Tue Apr  6 11:45:13 2004
+++ loncom/interface/statistics/lonproblemstatistics.pm	Fri Apr 16 17:43:56 2004
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonproblemstatistics.pm,v 1.83 2004/04/06 15:45:13 matthew Exp $
+# $Id: lonproblemstatistics.pm,v 1.84 2004/04/16 21:43:56 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -55,6 +55,7 @@
 use Apache::lonhtmlcommon;
 use Apache::loncoursedata;
 use Apache::lonstatistics;
+use LONCAPA::lonmetadata();
 use Apache::lonlocal;
 use Spreadsheet::WriteExcel;
 use Apache::lonstathelpers();
@@ -1453,22 +1454,17 @@
     }
     #
     # Store in metadata if computations were done for all students
-    if ($Apache::lonstatistics::SelectedSections[0] eq 'all' &&
-        $data->{'num_students'} > 1) {
-        my %storestats;
-        #
+    if ($data->{'num_students'} > 1) {
+        my @Sections = @Apache::lonstatistics::SelectedSections;
+        my $sections = '"'.join(' ',@Sections).'"';
+        $sections =~ s/&+/_/g;  # Ensure no special characters
+        $data->{'sections'}=$sections;
+        $data->{'course'} = $ENV{'request.course.id'};
         my $urlres=(&Apache::lonnet::decode_symb($resource->{'symb'}))[2];
+        $data->{'urlres'}=$urlres;
+        my %storestats = 
+            &LONCAPA::lonmetadata::dynamic_metadata_storage($data);
         my ($dom,$user) = $urlres=~/^(\w+)\/(\w+)/; 
-        my $preamble = $courseid.'___'.$urlres.'___';
-        #
-        $storestats{$preamble.'timestamp'}  = time;
-        $storestats{$preamble.'stdno'}      = $data->{'num_students'};
-        $storestats{$preamble.'avetries'}   = $data->{'mean_tries'};
-        $storestats{$preamble.'difficulty'} = $data->{'deg_of_diff'};
-        if ($SelectedFields{'deg_of_disc'}) {
-            $storestats{$preamble.'discrimination'} = $data->{'deg_of_disc'};
-        }
-        #
         &Apache::lonnet::put('nohist_resevaldata',\%storestats,$dom,$user);
     }
     return $data;

--matthew1082151836--