[LON-CAPA-cvs] cvs: loncom /interface/statistics lonproblemanalysis.pm
matthew
lon-capa-cvs@mail.lon-capa.org
Mon, 06 Oct 2003 20:51:20 -0000
This is a MIME encoded message
--matthew1065473480
Content-Type: text/plain
matthew Mon Oct 6 16:51:20 2003 EDT
Modified files:
/loncom/interface/statistics lonproblemanalysis.pm
Log:
Works for analysis of simple option response problems currently. No
implementation of concept groups and no time-based graphs, just 1-3 tries
analysis. I'm still developing the modules structure so it's a bit of a mess.
--matthew1065473480
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20031006165120.txt"
Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.24 loncom/interface/statistics/lonproblemanalysis.pm:1.25
--- loncom/interface/statistics/lonproblemanalysis.pm:1.24 Mon Sep 29 17:13:23 2003
+++ loncom/interface/statistics/lonproblemanalysis.pm Mon Oct 6 16:51:20 2003
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonproblemanalysis.pm,v 1.24 2003/09/29 21:13:23 matthew Exp $
+# $Id: lonproblemanalysis.pm,v 1.25 2003/10/06 20:51:20 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -24,16 +24,12 @@
#
# http://www.lon-capa.org/
#
-# (Navigate problems for statistical reports
-# YEAR=2002
-# 5/12,7/26,9/7,11/22 Behrouz Minaei
-#
-###
package Apache::lonproblemanalysis;
use strict;
use Apache::lonnet();
+use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::loncoursedata();
use Apache::lonstatistics;
@@ -42,48 +38,203 @@
sub BuildProblemAnalysisPage {
my ($r,$c)=@_;
$r->print('<h2>'.&mt('Option Response Problem Analysis').'</h2>');
+ $r->print(&CreateInterface());
if (exists($ENV{'form.problemchoice'})) {
- # This is me getting around my own cleverness:
- &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
- undef);
+ $r->print('<hr />');
+ &Apache::lonstatistics::Gather_Full_Student_Data($r);
#
- my ($symb,$id) = &get_problem_symb(
+ my ($symb,$part,$resid) = &get_problem_symb(
&Apache::lonnet::unescape($ENV{'form.problemchoice'})
);
$r->print('<hr />');
my $resource = &get_resource_from_symb($symb);
if (defined($resource)) {
- $r->print('<table bgcolor="ffffff"><tr><td>'.
- # Oh this is dumb! Need to rewrite relative links
- # otherwise images (for example) will not show.
+ my %Data = &get_problem_data($resource->{'src'});
+ my $ORdata = $Data{$part.'.'.$resid};
+ ##
+ ## Render the problem for display
+ my $base;
+ ($base,undef) = ($resource->{'src'} =~ m|(.*/)[^/]*$|);
+ $base = "http://".$ENV{'SERVER_NAME'}.$base;
+ $r->print('</form>'.
+ '<table bgcolor="ffffff"><tr><td>'.
+ '<base href="'.$base.'" />'.
+# &Apache::loncommon::get_student_view
+# ($symb,$ENV{'user.name'},$ENV{'user.domain'},$ENV{'request.course.id'},'web').
&Apache::lonnet::ssi_body($resource->{'src'}).
- '</td></tr></table>');
+ '</td></tr></table>'.
+ '<form name="Statistics" method="post" action="/adm/statistics">');
+ ##
+ ## Analyze the problem
+ my @Data = &Apache::loncoursedata::get_optionresponse_data
+ (undef,$symb,$resid);
+ my $analysis_html = &DoTriesAnalysis(\@Data,$ORdata);
+ $r->print($analysis_html);
} else {
$r->print('resource is undefined');
}
$r->print('<ol>');
- $r->print("<li />render problem\n");
+ $r->print("<li /><strike>render problem</strike>\n");
+ $r->print("<li /><strike>Get student response data</strike>\n");
$r->print("<li />image tag for plot\n");
$r->print("<li />plot key\n");
$r->print('</ol>');
- $r->print("<pre>\nProblem choice = $symb $id\n</pre>\n");
$r->print('<hr />');
- }
- $r->print('<input type="hidden" name="analysisfirstcall" value="no" />');
- $r->print(&CreateInterface());
- if (! exists($ENV{'form.analysisfirstcall'})) {
- return;
+ } else {
+ $r->print('<h3>No Problem Selected</h3>');
}
# Okay, they asked for data, so make sure we get the latest data.
- &Apache::lonnet::logthis('got here for some reason');
-# &Apache::lonstatistics::Gather_Full_Student_Data($r);
$r->print(&OptionResponseProblemSelector());
}
+
+sub DoTriesAnalysis {
+ my ($Data,$ORdata) = @_;
+ my $mintries = 1;
+ my $maxtries = 3;
+ my %ResponseData = &analyze_option_data_by_tries($Data,
+ $mintries,$maxtries);
+ my @Foils = sort(keys(%ResponseData));
+ my %Row_Label;
+ foreach my $foilid (@Foils) {
+ my $value = $ORdata->{'Foiltext'}->{$foilid};
+ &Apache::lonnet::logthis('row label '.$foilid.' = '.$value);
+ $Row_Label{$foilid} = $ORdata->{'Foiltext'}->{$foilid};
+ }
+ my @Rows;
+ $Rows[0] = ['<td> </td>'];
+ for (my $i=$mintries;$i<=$maxtries;$i++) {
+ push (@{$Rows[0]},
+ '<th colspan="3">'.&mt('Attempt').' '.$i.'</th>');
+ }
+ $Rows[1] = ['<th>'.&mt('Foil').'</th>'];
+ for (my $i=$mintries;$i<=$maxtries;$i++) {
+ push (@{$Rows[1]},('<th>'.&mt('Correct').'</th>',
+ '<th>'.&mt('Incorrect').'</th>',
+ '<th>'.&mt('Percent Correct').'</th>',
+ ));
+ }
+ my @PlotData;
+ my @CumulativePlotData;
+ my $index = 1;
+ foreach my $foilid (@Foils) {
+ my @Data = ('<td>'.$index.' '.$Row_Label{$foilid}.'</td>');
+ for (my $i=$mintries;$i<=$maxtries;$i++) {
+ push(@Data,
+ ('<td>'.$ResponseData{$foilid}->[$i]->{'correct'}.'</td>',
+ '<td>'.$ResponseData{$foilid}->[$i]->{'incorrect'}.
+ '</td>',
+ '<td>'.
+ sprintf("%4.2f",
+ $ResponseData{$foilid}->[$i]->{'percent_corr'}).
+ '</td>'));
+ #
+ # Gather the per-attempt data
+ push (@{$PlotData[$i]->{'good'}},
+ $ResponseData{$foilid}->[$i]->{'percent_corr'});
+ push (@{$PlotData[$i]->{'bad'}},
+ 100-$ResponseData{$foilid}->[$i]->{'percent_corr'});
+ }
+ for (my $i=0;$i<=$maxtries;$i++) {
+ push (@{$CumulativePlotData[$i]->{'good'}},
+ $CumulativePlotData[-1]->{'good'}+
+ $ResponseData{$foilid}->[$i]->{'correct'});
+ push (@{$CumulativePlotData[$i]->{'bad'}},
+ $CumulativePlotData[-1]->{'bad'}+
+ $ResponseData{$foilid}->[$i]->{'incorrect'});
+ }
+ push(@Rows,\@Data);
+ } continue {
+ $index++;
+ }
+ my @Data = ('<td></td>');
+ for (my $i=$mintries;$i<=$maxtries;$i++) {
+ push(@Data,'<td colspan="3">'.&DrawGraph('Attempt '.$i,'Foil Number',
+ 'Percent Correct',100,
+ $PlotData[$i]->{'good'},
+ $PlotData[$i]->{'bad'}).'</td>');
+ }
+ push (@Rows,\@Data);
+ my $table = '<table border="1" >'."\n";
+ for (my $i=0; $i <=$#Rows;$i++) {
+ $table .= '<tr>'.join('',@{$Rows[$i]})."</tr>\n";
+ }
+ $table .= '</table>';
+ return ($table);
+}
+
+sub analyze_option_data_by_tries {
+ my ($data,$mintries,$maxtries) = @_;
+ my %Trydata;
+ $mintries = 1 if (! defined($mintries) || $mintries < 1);
+ $maxtries = $mintries if (! defined($maxtries) || $maxtries < $mintries);
+ foreach my $row (@$data) {
+ my ($grading,$submission,$time,$tries) = @$row;
+ my @Foilgrades = split('&',$grading);
+ my @Foilsubs = split('&',$submission);
+ for (my $numtries = 1; $numtries <= $maxtries; $numtries++) {
+ if ($tries == $numtries) {
+ foreach my $foilgrade (@Foilgrades) {
+ my ($foilid,$correct) = split('=',$foilgrade);
+ if ($correct) {
+ $Trydata{$foilid}->[$numtries]->{'correct'}++;
+ } else {
+ $Trydata{$foilid}->[$numtries]->{'incorrect'}++;
+ }
+ }
+ }
+ }
+ }
+ foreach my $foilid (keys(%Trydata)) {
+ foreach my $tryhash (@{$Trydata{$foilid}}) {
+ next if ((! exists($tryhash->{'correct'}) &&
+ ! exists($tryhash->{'incorrect'})) ||
+ ($tryhash->{'correct'} < 1 &&
+ $tryhash->{'incorrect'} < 1));
+ $tryhash->{'percent_corr'} = 100 *
+ ($tryhash->{'correct'} /
+ ($tryhash->{'correct'} + $tryhash->{'incorrect'})
+ );
+ }
+ }
+ return %Trydata;
+}
+
+sub DrawGraph {
+ my ($title,$xlabel,$ylabel,$MaxY,$values1,$values2)=@_;
+ $title = '' if (! defined($title));
+ $xlabel = '' if (! defined($xlabel));
+ $ylabel = '' if (! defined($ylabel));
+ $title = &Apache::lonnet::escape($title);
+ $xlabel = &Apache::lonnet::escape($xlabel);
+ $ylabel = &Apache::lonnet::escape($ylabel);
+ #
+ my $sendValues1 = join(',', @$values1);
+ my $sendValues2;
+ if (defined($values2)) {
+ $sendValues2 = join(',', @$values2);
+ }
+
+ my $sendCount = scalar(@$values1);
+ $MaxY =1 if ($MaxY < 1);
+ if ( int($MaxY) < $MaxY ) {
+ $MaxY++;
+ $MaxY = int($MaxY);
+ }
+ my @GData = ($title,$xlabel,$ylabel,$MaxY,$sendCount,$sendValues1);
+ if (defined($sendValues2)) {
+ push (@GData,$sendValues2);
+ }
+ return '<IMG src="/cgi-bin/graph.png?'.
+ (join('&', @GData)).'" border="1" />';
+}
+
+
+
sub get_problem_symb {
my $problemstring = shift();
- my ($symb,$id) = ($problemstring=~ /^(.*):([^:]*)$/);
- return ($symb,$id);
+ my ($symb,$partid,$resid) = ($problemstring=~ /^(.*):([^:]*):([^:]*)$/);
+ return ($symb,$partid,$resid);
}
sub CreateInterface {
@@ -140,7 +291,7 @@
my $respid = $partdata->{'ResponseIds'}->[$i];
my $resptype = $partdata->{'ResponseTypes'}->[$i];
if ($resptype eq 'option') {
- my $value = &Apache::lonnet::escape($res->{'symb'}.':'.$respid);
+ my $value = &Apache::lonnet::escape($res->{'symb'}.':'.$part.':'.$respid);
my $checked = '';
if ($ENV{'form.problemchoice'} eq $value) {
$checked = 'checked ';
@@ -168,10 +319,8 @@
sub get_resource_from_symb {
my ($symb) = @_;
- &Apache::lonnet::logthis('target symb = :'.$symb.':');
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
foreach my $res (@{$seq->{'contents'}}) {
- &Apache::lonnet::logthis('symb = :'.$res->{'symb'}.':');
if ($res->{'symb'} eq $symb) {
return $res;
}
@@ -180,46 +329,74 @@
return undef;
}
-=pod
-
-sub InitAnalysis {
- my ($resource,$sname,$sdom)=@_;
- my $symb = $resource->
- my $URI = $hash{'src_'.$rid};
-
- my $Answ=&Apache::lonnet::ssi($URI,('grade_target' => 'analyze',
- 'grade_username' => $sname,
- 'grade_domain' => $sdom,
- 'grade_courseid' => $cid,
- 'grade_symb' => $symb));
-# my $Answ=&Apache::lonnet::ssi($URI,('grade_target' => 'analyze'));
-
+sub get_problem_data {
+ my ($url) = @_;
+# my $Answ=&Apache::lonnet::ssi($URI,('grade_target' => 'analyze',
+# 'grade_username' => $sname,
+# 'grade_domain' => $sdom,
+# 'grade_courseid' => $cid,
+# 'grade_symb' => $symb));
+ my $Answ=&Apache::lonnet::ssi($url,('grade_target' => 'analyze'));
(my $garbage,$Answ)=split(/_HASH_REF__/,$Answ,2);
- %Answer=();
+ my %Answer;
%Answer=&Apache::lonnet::str2hash($Answ);
-
- my $parts='';
- foreach my $elm (@{$Answer{"parts"}}) {
- $parts.="$elm,";
- }
- chop($parts);
- my $conc='';
- foreach my $elm (@{$Answer{"$parts.concepts"}}) {
- $conc.="$elm@";
- }
- chop($conc);
-
- @Concepts=split(/\@/,$conc);
- foreach my $concept (@{$Answer{"$parts.concepts"}}) {
- foreach my $foil (@{$Answer{"$parts.concept.$concept"}}) {
- $foil_to_concept{$foil} = $concept;
- #$ConceptData{$foil} = $Answer{"$parts.foil.value.$foil"};
+# &Apache::lonnet::logthis('keys of %Answer = '.join(', ',(keys(%Answer))));
+# &Apache::lonnet::logthis('$Answer{parts} = '.
+# join(', ',@{$Answer{'parts'}}));
+ my %Partdata;
+ foreach my $part (@{$Answer{'parts'}}) {
+ while (my($key,$value) = each(%Answer)) {
+ next if ($key !~ /^$part/);
+ $key =~ s/^$part\.//;
+ if (ref($value) eq 'ARRAY') {
+ if ($key eq 'options') {
+ $Partdata{$part}->{'Options'}=$value;
+ } elsif ($key eq 'concepts') {
+ $Partdata{$part}->{'Concepts'}=$value;
+ } elsif ($key =~ /^concept\.(.*)$/) {
+ my $concept = $1;
+ foreach my $foil (@$value) {
+ $Partdata{$part}->{$foil}->{'Concept'}=$concept;
+ }
+ }
+ &Apache::lonnet::logthis($part.' '.$key.' (array) = '.
+ join(', ',@$value));
+ } else {
+ $value =~ s/^\s*//g;
+ $value =~ s/\s*$//g;
+ if ($key=~ /^foil\.text\.(.*)$/) {
+ my $foil = $1;
+ $Partdata{$part}->{'Foiltext'}->{$foil}=$value;
+ } elsif ($key =~ /^foil\.value\.(.*)$/) {
+ my $foil = $1;
+ $Partdata{$part}->{'FoilValues'}->{$foil}=$value;
+ }
+ &Apache::lonnet::logthis($part.' '.$key.' = '.$value);
+ }
}
}
- return $symb;
-}
-=cut
+# my $parts='';
+# foreach my $elm (@{$Answer{"parts"}}) {
+# $parts.="$elm,";
+# }
+# chop($parts);
+# my $conc='';
+# foreach my $elm (@{$Answer{"$parts.concepts"}}) {
+# $conc.="$elm@";
+# }
+# chop($conc);
+#
+# @Concepts=split(/\@/,$conc);
+# foreach my $concept (@{$Answer{"$parts.concepts"}}) {
+# foreach my $foil (@{$Answer{"$parts.concept.$concept"}}) {
+# $foil_to_concept{$foil} = $concept;
+# #$ConceptData{$foil} = $Answer{"$parts.foil.value.$foil"};
+# }
+# }
+# return $symb;
+ return %Partdata;
+}
1;
--matthew1065473480--