Annotation of loncom/interface/statistics/lonsurveyreports.pm, revision 1.3
1.1 matthew 1: # The LearningOnline Network with CAPA
2: #
1.3 ! matthew 3: # $Id: lonsurveyreports.pm,v 1.2 2004/07/06 15:56:42 matthew Exp $
1.1 matthew 4: #
5: # Copyright Michigan State University Board of Trustees
6: #
7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
8: #
9: # LON-CAPA is free software; you can redistribute it and/or modify
10: # it under the terms of the GNU General Public License as published by
11: # the Free Software Foundation; either version 2 of the License, or
12: # (at your option) any later version.
13: #
14: # LON-CAPA is distributed in the hope that it will be useful,
15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: # GNU General Public License for more details.
18: #
19: # You should have received a copy of the GNU General Public License
20: # along with LON-CAPA; if not, write to the Free Software
21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22: #
23: # /home/httpd/html/adm/gpl.txt
24: #
25: # http://www.lon-capa.org/
26: #
27: package Apache::lonsurveyreports;
28:
29: use strict;
30: use Apache::lonnet();
31: use Apache::loncommon();
32: use Apache::lonhtmlcommon();
33: use Apache::loncoursedata();
34: use Apache::lonstatistics;
35: use Apache::lonlocal;
36: use Apache::lonstathelpers;
37: use HTML::Entities();
38: use Time::Local();
39:
40: my @SubmitButtons = ({ name => 'PrevProblem',
41: text => 'Previous Survey' },
42: { name => 'NextProblem',
43: text => 'Next Survey' },
44: { name => 'break'},
45: { name => 'SelectAnother',
46: text => 'Choose a different Survey Problem' },
47: { name => 'Generate',
48: text => 'Generate Report'},
49: );
50:
51: sub BuildSurveyReportsPage {
52: my ($r,$c)=@_;
53: #
54: my %Saveable_Parameters = ('Status' => 'scalar',
55: 'Section' => 'array',
56: 'NumPlots' => 'scalar',
57: );
58: &Apache::loncommon::store_course_settings('survey_reports',
59: \%Saveable_Parameters);
60: &Apache::loncommon::restore_course_settings('survey_resports',
61: \%Saveable_Parameters);
62: #
63: &Apache::lonstatistics::PrepareClasslist();
64: #
65: $r->print(&CreateInterface());
66: #
67: my @Students = @Apache::lonstatistics::Students;
68: #
69: if (@Students < 1) {
70: $r->print('<h2>There are no students in the sections selected</h2>');
71: }
72: #
73: my @CacheButtonHTML =
74: &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status');
75: $r->rflush();
76: #
77: if (exists($ENV{'form.problemchoice'}) &&
78: ! exists($ENV{'form.SelectAnother'})) {
79: foreach my $button (@SubmitButtons) {
80: if ($button->{'name'} eq 'break') {
81: $r->print("<br />\n");
82: } else {
83: $r->print('<input type="submit" name="'.$button->{'name'}.'" '.
84: 'value="'.&mt($button->{'text'}).'" />');
85: $r->print(' 'x5);
86: }
87: }
88: foreach my $html (@CacheButtonHTML) {
89: $r->print($html.(' 'x5));
90: }
91: #
92: $r->print('<hr />');
93: $r->rflush();
94: #
95: # Determine which problem we are to analyze
96: my $current_problem = &Apache::lonstathelpers::get_target_from_id
97: ($ENV{'form.problemchoice'});
98: #
1.3 ! matthew 99: my ($navmap,$prev,$curr,$next) =
1.1 matthew 100: &Apache::lonstathelpers::get_prev_curr_next($current_problem,
101: '.',
102: 'part_survey',
103: );
104: if (exists($ENV{'form.PrevProblem'}) && defined($prev)) {
105: $current_problem = $prev;
106: } elsif (exists($ENV{'form.NextProblem'}) && defined($next)) {
107: $current_problem = $next;
108: } else {
109: $current_problem = $curr;
110: }
111: #
112: # Store the current problem choice and send it out in the form
113: $ENV{'form.problemchoice'} =
114: &Apache::lonstathelpers::make_target_id($current_problem);
115: $r->print('<input type="hidden" name="problemchoice" value="'.
116: $ENV{'form.problemchoice'}.'" />');
117: #
118: if (! defined($current_problem->{'resource'})) {
119: $r->print('resource is undefined');
120: } else {
121: my $resource = $current_problem->{'resource'};
1.3 ! matthew 122: $r->print('<h1>'.$resource->compTitle.'</h1>');
! 123: $r->print('<h3>'.$resource->src.'</h3>');
1.1 matthew 124: $r->print(&Apache::lonstathelpers::render_resource($resource));
125: $r->rflush();
126: my %Data = &Apache::lonstathelpers::get_problem_data
1.3 ! matthew 127: ($resource->src);
1.1 matthew 128: &make_HTML_report($r,$current_problem,\%Data,\@Students);
129: }
130: $r->print('<hr />');
131: } else {
132: $r->print('<input type="submit" name="Generate" value="'.
133: &mt('Generate Survey Report').'" />');
134: $r->print(' 'x5);
135: $r->print('<h3>'.&mt('Please select a Survey to analyze').'</h3>');
136: $r->print(&SurveyProblemSelector());
137: }
138: }
139:
140: ##########################################################
141: ##########################################################
142: ##
143: ## SurveyProblemSelector
144: ##
145: ##########################################################
146: ##########################################################
147: sub SurveyProblemSelector {
148: my $Str = '';
149: my @SurveyProblems;
1.3 ! matthew 150: my ($navmap,@sequences) =
! 151: &Apache::lonstatistics::selected_sequences_with_assessments('all');
! 152: foreach my $seq (@sequences) {
! 153: my @resources = &Apache::lonstathelpers::get_resources($navmap,$seq);
! 154: foreach my $res (@resources) {
! 155: foreach my $part (@{$res->parts}) {
! 156: if ($res->is_survey($part)) {
1.1 matthew 157: push(@SurveyProblems,{res=>$res,seq=>$seq,part=>$part});
158: last;
159: }
160: }
161: }
162: }
163: if (! scalar(@SurveyProblems)) {
164: $Str = '<h1>'.
165: &mt('There are no survey problems in this course').
166: '</h1>'.$/;
167: return $Str;
168: }
169: $Str .= '<table>'.$/;
170: $Str .= '<tr>'.'<td></td>'.
1.3 ! matthew 171: '<th>'.&mt('Survey').'</th>'.
1.1 matthew 172: '</tr>'.$/;
1.3 ! matthew 173: my $id;
1.1 matthew 174: foreach my $problem (@SurveyProblems) {
1.3 ! matthew 175: $id++;
1.1 matthew 176: my $value = &Apache::lonstathelpers::make_target_id
1.3 ! matthew 177: ({symb=>$problem->{'res'}->symb,
1.1 matthew 178: part=>$problem->{'part'},
179: respid=>undef,
180: resptype=>undef});
181: my $checked = '';
182: if ($ENV{'form.problemchoice'} eq $value) {
183: $checked = 'checked ';
184: }
1.3 ! matthew 185: my $link = $problem->{'res'}->src.
! 186: '?symb='.&Apache::lonnet::escape($problem->{'res'}->symb);
! 187: $Str .= '<tr><td>'.
! 188: '<input type="radio" name="problemchoice" id="'.$id.'" '.
1.1 matthew 189: 'value="'.$value.'" '.$checked.'/>'.'</td>'.
1.3 ! matthew 190: '<td><nobr>'.
! 191: '<label for="'.$id.'">'.$problem->{'res'}->compTitle.'('.$problem->{'seq'}->compTitle.')'.'</lablel>'.
! 192: (' 'x2).
! 193: qq{<a target="preview" href="$link">view</a>}.'</td></tr>'.$/;
1.1 matthew 194: }
195: $Str .= '</table>';
196: return $Str;
197: }
198:
199: #########################################################
200: #########################################################
201: ##
202: ## Compile Student Answers
203: ##
204: #########################################################
205: #########################################################
206: sub Compile_Student_Answers {
207: my ($problem,$ProblemData,$Students) = @_;
208: my $resource = $problem->{'resource'};
209: foreach my $student (@$Students) {
1.3 ! matthew 210: foreach my $partid (@{$resource->parts}) {
! 211: my @response_ids = $resource->responseIds($partid);
! 212: my @response_types = $resource->responseType($partid);
! 213: for (my $i=0;$i<=$#response_ids;$i++) {
! 214: my $respid = $response_ids[$i];
! 215: my $resptype = $response_types[$i];
1.1 matthew 216: my $results =
217: &Apache::loncoursedata::get_response_data_by_student
1.3 ! matthew 218: ($student,$resource->symb,$respid);
1.1 matthew 219: next if (! defined($results) || ref($results) ne 'ARRAY' ||
220: ref($results->[0]) ne 'ARRAY');
221: my $student_response =
222: $results->[0]->[&Apache::loncoursedata::RDs_submission()];
223: $problem->{'responsedata'}->{$partid}->{$respid}->{'_count'}++;
224: my $data = $problem->{'responsedata'}->{$partid}->{$respid};
1.3 ! matthew 225: if ($resptype =~ /^(option|match)$/) {
! 226: my @responses = split('&',$student_response);
! 227: foreach my $response (@responses) {
! 228: my ($foilid,$option) =
! 229: map {
! 230: &Apache::lonnet::unescape($_);
! 231: } split('=',$response);
! 232: $data->{'foil_count'}->{$foilid}++;
! 233: $data->{'foil_responses'}->{$foilid}->{$option}++;
! 234: }
! 235: } elsif ($resptype =~ /^(radiobutton)$/) {
! 236: my ($foil,$value) = map { &Apache::lonnet::unescape($_); } split('=',$student_response);
1.1 matthew 237: $value += 1; # explicitly increment it...
238: $data->{'foil_responses'}->{$foil}++;
239: $data->{'foil_values'}->{$value}++;
240: if (! exists($data->{'map'}->{$value})) {
241: $data->{'map'}->{$value} = $foil;
242: }
243: } else {
244: # Variable stuff (essays, raw numbers, strings) go here
245: push(@{$data->{'responses'}},$student_response);
246: }
247: }
248: }
249: }
250: return;
251: }
252:
253: #########################################################
254: #########################################################
255: ##
256: ## make_HTML_report
257: ##
258: #########################################################
259: #########################################################
260: sub make_HTML_report {
261: my ($r,$problem,$ProblemData,$Students) = @_;
262: &Compile_Student_Answers($problem,$ProblemData,$Students);
263: # &output_hash('',$ProblemData);
264: my $resource = $problem->{'resource'};
1.3 ! matthew 265: foreach my $partid (@{$resource->parts}) {
! 266: my @response_ids = $resource->responseIds($partid);
! 267: my @response_types = $resource->responseType($partid);
! 268: for (my $i=0;$i<=$#response_ids;$i++) {
1.1 matthew 269: my $Str = '<table>'.$/;
1.3 ! matthew 270: my $respid = $response_ids[$i];
! 271: my $resptype = $response_types[$i];
1.1 matthew 272: my $data = $problem->{'responsedata'}->{$partid}->{$respid};
1.3 ! matthew 273: if (! defined($data) || ref($data) ne 'HASH') {
! 274: next;
! 275: }
1.1 matthew 276: # Debugging code
277: # $Str .= '<tr>'.
278: # '<td>'.$partid.'</td>'.
279: # '<td>'.$respid.'</td>'.
280: # '<td>'.$resptype.'</td>'.
281: # '</tr>'.$/;
282: $Str .= '<tr>'.
283: '<td><b>'.&mt('Total').'</b></td>'.
284: '<td>'.$data->{'_count'}.'</td>'.
1.2 matthew 285: '<td>'.&mt('Part [_1], Response [_2]',$partid,$respid).'</td>'.
1.3 ! matthew 286: '</tr>';
1.1 matthew 287: if (exists($data->{'responses'}) &&
288: ref($data->{'responses'}) eq 'ARRAY') {
289: &randomize_array($data->{'responses'});
290: foreach my $response (@{$data->{'responses'}}) {
291: $response =~ s/\\r\\n/\n/g;
292: $response =~ s/\\'/'/g;
293: $response =~ s/\\"/"/g;
294: $Str .= '<tr>'.
295: '<td colspan="3"><pre>'.
296: &HTML::Entities::encode($response,'<>&').
297: '</pre><hr /></td>'.
298: '</tr>'.$/;
299: }
1.3 ! matthew 300: } elsif (exists($data->{'foil_count'}) &&
! 301: exists($data->{'foil_responses'})) {
! 302: $Str.='<tr><td colspan="3">'.
! 303: '<table><tr>';
! 304: my $tmp = '<th>'.join('</th><th>',
! 305: (&mt('Foil Name'),
! 306: &mt('Foil Text'),
! 307: &mt('Option'),
! 308: &mt('Frequency'),
! 309: &mt('Percent'))).'</th></tr>';
! 310: my @foils = sort(keys(%{$data->{'foil_responses'}}));
! 311: foreach my $foilid (@foils) {
! 312: my $prob_data = $ProblemData->{$partid.'.'.$respid};
! 313: my $foil_count = $data->{'foil_count'}->{$foilid};
! 314: my $foiltext = $prob_data->{'_Foils'}->{$foilid}->{'text'};
! 315: my $foilname = $prob_data->{'_Foils'}->{$foilid}->{'name'};
! 316: my $rowspan = scalar(@{$prob_data->{'_Options'}});
! 317: my $preamble = '<tr>'.
! 318: '<td valign="top" rowspan="'.$rowspan.'">'.
! 319: $foilname.'</td>'.
! 320: '<td valign="top" rowspan="'.$rowspan.'">'.
! 321: $foiltext.'</td>';
! 322: foreach my $option (sort(@{$prob_data->{'_Options'}})){
! 323: my $count =
! 324: $data->{'foil_responses'}->{$foilid}->{$option};
! 325: $tmp .= $preamble.
! 326: '<td>'.$option.'</td>'.
! 327: '<td align="right">'.$count.'</td>'.
! 328: '<td align="right">'.
! 329: sprintf('%.2f',100*$count/$foil_count).'%'.
! 330: '</td></tr>'.$/;
! 331: $preamble = '<tr>';
! 332: }
! 333: }
! 334: $Str.=$tmp.'</table></td></tr>';
1.1 matthew 335: } elsif (exists($data->{'_count'}) &&
336: exists($data->{'foil_values'}) &&
337: exists($data->{'map'})) {
338: # This is an option or radiobutton survey response
339: my $total = $data->{'_count'};
340: my $sum = 0;
341: my $tmp;
342: foreach my $value (sort(keys(%{$data->{'foil_values'}}))) {
343: my $count = $data->{'foil_values'}->{$value};
344: my $foilid = $data->{'map'}->{$value};
345: my $foiltext = $ProblemData->{$partid.'.'.$respid}->{'_Foils'}->{$foilid}->{'text'};
346: my $foilname = $ProblemData->{$partid.'.'.$respid}->{'_Foils'}->{$foilid}->{'name'};
347: $sum = $value * $data->{'foil_values'}->{$value};
348: $tmp .= '<tr>'.
349: '<td>'.$foilname.'</td>'.
350: '<td>'.$foiltext.'</td>'.
351: '<td align="right">'.$count.'</td>'.
352: '<td align="right">'.
353: sprintf("%.2f",$count/$total*100).'%</td>'.
354: '</tr>'.$/;
355: }
356: $Str .= '<tr>'.
357: '<th>'.&mt('Foil Name').'</th>'.
358: '<th>'.&mt('Text').'</th>'.
359: '<th>'.&mt('Freq').'</th>'.
360: '<th>'.&mt('Percent').'</th>'.
361: '</tr>'.$/.
362: $tmp;
363: }
364: $Str.= '</table><hr />';
365: $r->print($Str);
366: $r->rflush();
367: }
368: }
369: return;
370: }
371:
372: sub randomize_array {
373: # Fisher Yates shuffle, lifted from p 121 of "The Perl Cookbook"
374: my ($array) = @_;
375: for (my $i=scalar(@$array);--$i;) {
376: my $j = int(rand($i+1));
377: next if ($i == $j);
378: @$array[$i,$j]=@$array[$j,$i];
379: }
380: }
381:
382: #########################################################
383: #########################################################
384: ##
385: ## Generic Interface Routines
386: ##
387: #########################################################
388: #########################################################
389: sub CreateInterface {
390: ##
391: ## Environment variable initialization
392: my $Str = '';
393: $Str .= &Apache::lonhtmlcommon::breadcrumbs
394: (undef,'Student Submission Reports');
395: $Str .= '<p>';
396: $Str .= '<table cellspacing="5">'."\n";
397: $Str .= '<tr>';
398: $Str .= '<td align="center"><b>'.&mt('Sections').'</b></td>';
399: $Str .= '<td align="center"><b>'.&mt('Enrollment Status').'</b></td>';
400: $Str .= '</tr>'."\n";
401: #
402: $Str .= '<tr><td align="center">'."\n";
403: $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
404: $Str .= '</td>';
405: #
406: $Str .= '<td align="center">';
407: $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5);
408: $Str .= '</td>';
409: #
410: $Str .= '</tr>'."\n";
411: $Str .= '</table>'."\n";
412: #
413: $Str .= '<nobr>'.&mt('Status: [_1]',
414: '<input type="text" '.
415: 'name="stats_status" size="60" value="" />').
416: '</nobr>'.'</p>';
417: ##
418: return $Str;
419: }
420:
421: 1;
422:
423: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>