--- loncom/interface/statistics/lonproblemstatistics.pm 2004/03/29 19:41:24 1.76
+++ loncom/interface/statistics/lonproblemstatistics.pm 2012/05/12 03:17:43 1.122.2.1
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonproblemstatistics.pm,v 1.76 2004/03/29 19:41:24 matthew Exp $
+# $Id: lonproblemstatistics.pm,v 1.122.2.1 2012/05/12 03:17:43 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -50,17 +50,21 @@ Excel files, and plots.
package Apache::lonproblemstatistics;
use strict;
-use Apache::lonnet();
+use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
use Apache::loncoursedata;
use Apache::lonstatistics;
+use LONCAPA::lonmetadata();
use Apache::lonlocal;
use Spreadsheet::WriteExcel;
use Apache::lonstathelpers();
use Time::HiRes;
+use LONCAPA;
+
my @StatsArray;
+my %SeqStat; # keys are symbs, values are hash refs
##
## Localization notes:
@@ -69,13 +73,42 @@ my @StatsArray;
## header for plots created with Graph.pm, both of which more than likely do
## not support localization.
##
+#
+#
+##
+## Description of Field attributes
+##
+## Attribute Required Value Meaning or Use
+##
+## name yes any scalar Used to uniquely identify field
+## title yes any scalar This is what the user sees to identify
+## the field. Passed through &mt().
+## long_title yes any scalar Used as graph heading and in excel
+## output. NOT translated
+## align no (left|right|center) HTML cell contents alignment
+## color yes html color HTML cell background color
+## used to visually group statistics
+## special no (link) Indicates a link, target is name.link
+## Currently set in &get_statistics()
+## graphable no (yes|no) Can a bar graph of the field be
+## produced?
+## sortable no (yes|no) Should a sort link be put in the
+## column header?
+## selectable yes (yes|no) Can the column be removed from the
+## statistics display?
+## selected yes (yes|no) Is the column selected by default?
+##
+## format no sprintf format string
+##
+## excel_format no excel format type
+## (see &Apache::loncommon::define_excel_formats
my @Fields = (
{ name => 'problem_num',
title => 'P#',
align => 'right',
color => '#FFFFE6',
selectable => 'no',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'container',
title => 'Sequence or Folder',
@@ -83,23 +116,23 @@ my @Fields = (
color => '#FFFFE6',
sortable => 'yes',
selectable => 'no',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'title',
title => 'Title',
align => 'left',
color => '#FFFFE6',
special => 'link',
- sortable => 'yes',
+ sortable => 'yes',
selectable => 'no',
- selected => 'yes',
+ defaultselected => 'yes',
},
- { name => 'part',
+ { name => 'part',
title => 'Part',
align => 'left',
color => '#FFFFE6',
selectable => 'no',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'num_students',
title => '#Stdnts',
@@ -110,7 +143,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Number of Students Attempting Problem',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'tries',
title => 'Tries',
@@ -121,7 +154,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Total Number of Tries',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'max_tries',
title => 'Max Tries',
@@ -132,7 +165,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Maximum Number of Tries',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'min_tries',
title => 'Min Tries',
@@ -143,7 +176,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Minumum Number of Tries',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'mean_tries',
title => 'Mean Tries',
@@ -154,7 +187,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Average Number of Tries',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'std_tries',
title => 'S.D. tries',
@@ -165,7 +198,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Standard Deviation of Number of Tries',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'skew_tries',
title => 'Skew Tries',
@@ -176,7 +209,7 @@ my @Fields = (
graphable => 'yes',
long_title => 'Skew of Number of Tries',
selectable => 'yes',
- selected => 'no',
+ defaultselected => 'no',
},
{ name => 'num_solved',
title => '#YES',
@@ -186,8 +219,8 @@ my @Fields = (
sortable => 'yes',
graphable => 'yes',
long_title => 'Number of Students able to Solve',
- selectable => 'no',
- selected => 'yes',
+ selectable => 'yes',
+ defaultselected => 'yes',
},
{ name => 'num_override',
title => '#yes',
@@ -198,7 +231,18 @@ my @Fields = (
graphable => 'yes',
long_title => 'Number of Students given Override',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
+ },
+ { name => 'tries_per_correct',
+ title => 'tries/correct',
+ align => 'right',
+ color => '#FFDDDD',
+ format => '%4.1f',
+ sortable => 'yes',
+ graphable => 'yes',
+ long_title => 'Tries per Correct Answer',
+ selectable => 'yes',
+ defaultselected => 'yes',
},
{ name => 'num_wrong',
title => '#Wrng',
@@ -207,9 +251,20 @@ my @Fields = (
format => '%4.1f',
sortable => 'yes',
graphable => 'yes',
+ long_title => 'Number of students whose final answer is wrong',
+ selectable => 'yes',
+ defaultselected => 'yes',
+ },
+ { name => 'per_wrong',
+ title => '%Wrng',
+ align => 'right',
+ color => '#FFDDDD',
+ format => '%4.1f',
+ sortable => 'yes',
+ graphable => 'yes',
long_title => 'Percent of students whose final answer is wrong',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'deg_of_diff',
title => 'DoDiff',
@@ -221,7 +276,7 @@ my @Fields = (
long_title => 'Degree of Difficulty'.
'[ 1 - ((#YES+#yes) / Tries) ]',
selectable => 'yes',
- selected => 'yes',
+ defaultselected => 'yes',
},
{ name => 'deg_of_disc',
title => 'DoDisc',
@@ -232,7 +287,229 @@ my @Fields = (
graphable => 'yes',
long_title => 'Degree of Discrimination',
selectable => 'yes',
- selected => 'no',
+ defaultselected => 'yes',
+ },
+## duedate included for research purposes. Commented out most of the time.
+# { name => 'duedate',
+# title => 'Due Date',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'yes',
+# graphable => 'no',
+# long_title => 'Due date of resource for instructor',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+## opendate included for research purposes. Commented out most of the time.
+# { name => 'opendate',
+# title => 'Open Date',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'yes',
+# graphable => 'no',
+# long_title => 'date resource became answerable',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+## symb included for research purposes. Commented out most of the time.
+# { name => 'symb',
+# title => 'Symb',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'yes',
+# graphable => 'no',
+# long_title => 'Unique LON-CAPA identifier for problem',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+## resptypes included for research purposes. Commented out most of the time.
+# { name => 'resptypes',
+# title => 'Response Types',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'no',
+# graphable => 'no',
+# long_title => 'Response Types used in this problem',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+## maxtries included for research purposes. Commented out most of the time.
+# { name => 'maxtries',
+# title => 'Maxtries',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'no',
+# graphable => 'no',
+# long_title => 'Maximum number of tries',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+## hinttries included for research purposes. Commented out most of the time.
+# { name => 'hinttries',
+# title => 'hinttries',
+# align => 'left',
+# color => '#FFFFFF',
+# sortable => 'no',
+# graphable => 'no',
+# long_title => 'Number of tries before a hint appears',
+# selectable => 'no',
+# defaultselected => 'yes',
+# },
+#
+## problem weight for instructor
+ { name => 'weight',
+ title => 'weight',
+ align => 'right',
+ color => '#FFFFFF',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Problem weight (for instructor)',
+ selectable => 'yes',
+ defaultselected => 'yes',
+ },
+);
+
+my @SeqFields = (
+ { name => 'title',
+ title => 'Sequence',
+ align => 'left',
+ color => '#FFFFE6',
+ special => 'no',
+ sortable => 'no',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'items',
+ title => '#Items',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4d',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Number of Items in Sequence',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'scoremean',
+ title => 'Score Mean',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Mean Sequence Score',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'scorestd',
+ title => 'Score STD',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Standard Deviation of Sequence Scores',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'scoremax',
+ title => 'Score Max',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Maximum Sequence Score',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'scoremin',
+ title => 'Score Min',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Minumum Sequence Score',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'scorecount',
+ title => 'Score N',
+ align => 'right',
+ color => '#FFFFE6',
+ format => '%4d',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Number of Students in score computations',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'countmean',
+ title => 'Count Mean',
+ align => 'right',
+ color => '#FFFFFF',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Mean Sequence Score',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'countstd',
+ title => 'Count STD',
+ align => 'right',
+ color => '#FFFFFF',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Standard Deviation of Sequence Scores',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'countmax',
+ title => 'Count Max',
+ align => 'right',
+ color => '#FFFFFF',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Maximum Number of Correct Problems',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'countmin',
+ title => 'Count Min',
+ align => 'right',
+ color => '#FFFFFF',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Minumum Number of Correct Problems',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'count',
+ title => 'Count N',
+ align => 'right',
+ color => '#FFFFFF',
+ format => '%4d',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'Number of Students in score computations',
+ selectable => 'yes',
+ defaultselected => 'no',
+ },
+ { name => 'KR-21',
+ title => 'KR-21',
+ align => 'right',
+ color => '#FFAAAA',
+ format => '%4.2f',
+ sortable => 'no',
+ graphable => 'no',
+ long_title => 'KR-21 reliability statistic',
+ selectable => 'yes',
+ defaultselected => 'no',
},
);
@@ -241,38 +518,66 @@ my %SelectedFields;
sub parse_field_selection {
#
# Pull out the defaults
- if (! defined($ENV{'form.fieldselections'})) {
- $ENV{'form.fieldselections'} = [];
+ if (! defined($env{'form.fieldselections'})) {
+ $env{'form.fieldselections'} = [];
foreach my $field (@Fields) {
next if ($field->{'selectable'} ne 'yes');
- if ($field->{'selected'} eq 'yes') {
- push(@{$ENV{'form.fieldselections'}},$field->{'name'});
+ if ($field->{'defaultselected'} eq 'yes') {
+ push(@{$env{'form.fieldselections'}},$field->{'name'});
}
}
}
#
+ # Make sure the data we are plotting is there
+ my %NeededFields;
+ if (exists($env{'form.plot'}) && $env{'form.plot'} ne '' &&
+ $env{'form.plot'} ne 'none') {
+ if ($env{'form.plot'} eq 'degrees') {
+ $NeededFields{'deg_of_diff'}++;
+ $NeededFields{'deg_of_disc'}++;
+ } elsif ($env{'form.plot'} eq 'tries statistics') {
+ $NeededFields{'mean_tries'}++;
+ $NeededFields{'std_tries'}++;
+ $NeededFields{'problem_num'}++;
+ } else {
+ $NeededFields{$env{'form.plot'}}++;
+ }
+ }
+ #
# This should not happen, but in case it does...
- if (ref($ENV{'form.fieldselections'}) ne 'ARRAY') {
- $ENV{'form.fieldselections'} = [$ENV{'form.fieldselections'}];
+ if (ref($env{'form.fieldselections'}) ne 'ARRAY') {
+ $env{'form.fieldselections'} = [$env{'form.fieldselections'}];
}
#
# Set the field data and the selected fields (for easier checking)
undef(%SelectedFields);
foreach my $field (@Fields) {
- next if ($field->{'selectable'} ne 'yes');
- $field->{'selected'} = 'no';
- foreach my $selection (@{$ENV{'form.fieldselections'}}) {
+ if ($field->{'selectable'} ne 'yes') {
+ $field->{'selected'} = 'yes';
+ } else {
+ $field->{'selected'} = 'no';
+ }
+ if (exists($NeededFields{$field->{'name'}})) {
+ $field->{'selected'} = 'yes';
+ $SelectedFields{$field->{'name'}}++;
+ }
+ foreach my $selection (@{$env{'form.fieldselections'}}) {
if ($selection eq $field->{'name'} || $selection eq 'all') {
$field->{'selected'} = 'yes';
$SelectedFields{$field->{'name'}}++;
}
}
}
+ #
+ # Always show all the sequence statistics (for now)
+ foreach my $field (@SeqFields) {
+ $field->{'selected'} = 'yes';
+ }
return;
}
sub field_selection_input {
- my $Str = '
';
$Str .= '';
- $Str .= ' 'x5;
- $Str .= 'Plot '.&plot_dropdown().(' 'x10);
- $Str .= '';
- $Str .= ' 'x5;
- $Str .= '';
- $Str .= ' 'x5;
- $Str .= '';
- $Str .= ' 'x5;
+ $Str .= (' 'x10);
+ #
return $Str;
}
@@ -362,14 +664,26 @@ Main interface to problem statistics.
###############################################
###############################################
+my $navmap;
+my @sequences;
+
+sub clean_up {
+ undef($navmap);
+ undef(@sequences);
+}
+
sub BuildProblemStatisticsPage {
my ($r,$c)=@_;
+ undef($navmap);
+ undef(@sequences);
#
my %Saveable_Parameters = ('Status' => 'scalar',
'statsoutputmode' => 'scalar',
'Section' => 'array',
+ 'Groups' => 'array',
'StudentData' => 'array',
- 'Maps' => 'array');
+ 'Maps' => 'array',
+ 'fieldselections'=> 'array');
&Apache::loncommon::store_course_settings('statistics',
\%Saveable_Parameters);
&Apache::loncommon::restore_course_settings('statistics',
@@ -379,30 +693,36 @@ sub BuildProblemStatisticsPage {
#
# Clear the package variables
undef(@StatsArray);
+ undef(%SeqStat);
#
# Finally let the user know we are here
- my $interface = &CreateInterface();
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs('Overall Problem Statistics',
+ 'Statistics_Overall_Key'));
+
+ my $interface = &CreateInterface($r);
$r->print($interface);
- $r->print('');
#
- if (! exists($ENV{'form.statsfirstcall'})) {
- $r->print('');
- $r->print('
'.
+ my @CacheButtonHTML =
+ &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status');
+ my $Str;
+ foreach my $html (@CacheButtonHTML) {
+ $Str.=$html.(' 'x5);
+ }
+ #
+ $r->print($Str);
+ if (! exists($env{'form.firstrun'})) {
+ $r->print('
'.
&mt('Press "Generate Statistics" when you are ready.').
- '
'.
+ '
'.
+ '
'.
&mt('It may take some time to update the student data '.
- 'for the first analysis. Future analysis this session '.
- ' will not have this delay.').
+ 'for the first analysis. Future analysis this session '.
+ 'will not have this delay.').
'
');
+ &clean_up();
return;
- } elsif ($ENV{'form.statsfirstcall'} eq 'yes' ||
- exists($ENV{'form.UpdateCache'}) ||
- exists($ENV{'form.ClearCache'}) ) {
- $r->print('');
- &Apache::lonstatistics::Gather_Student_Data($r);
- } else {
- $r->print('');
}
$r->rflush();
#
@@ -410,12 +730,31 @@ sub BuildProblemStatisticsPage {
# it does not slow things down noticably.
&Apache::loncoursedata::populate_weight_table();
#
- if (exists($ENV{'form.Excel'})) {
+ ($navmap,@sequences) =
+ &Apache::lonstatistics::selected_sequences_with_assessments();
+ if (! ref($navmap)) {
+ $r->print('
\n";
my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits();
if (defined($starttime) || defined($endtime)) {
@@ -513,8 +874,8 @@ sub html_preamble {
&Apache::lonlocal::locallocaltime($endtime)
).'';
}
- $Str .= "
".&mt('Compiled on [_1]',
- &Apache::lonlocal::locallocaltime(time))."
";
+ $Str .= "
".&mt('Compiled on [_1]',
+ &Apache::lonlocal::locallocaltime(time))."
";
return $Str;
}
@@ -532,7 +893,7 @@ sub statistics_html_table_data {
foreach my $field (@Fields) {
next if ($options =~ /no $field->{'name'}/);
next if ($field->{'selected'} ne 'yes');
- $row .= '