Annotation of loncom/interface/statistics/lonsubmissiontimeanalysis.pm, revision 1.1

1.1     ! matthew     1: # The LearningOnline Network with CAPA
        !             2: #
        !             3: # $Id$
        !             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: 
        !            28: package Apache::lonsubmissiontimeanalysis;
        !            29: 
        !            30: use strict;
        !            31: use Apache::lonnet();
        !            32: use Apache::loncommon();
        !            33: use Apache::lonhtmlcommon();
        !            34: use Apache::loncoursedata();
        !            35: use Apache::lonstatistics;
        !            36: use Apache::lonlocal;
        !            37: use HTML::Entities();
        !            38: use Time::Local();
        !            39: use Spreadsheet::WriteExcel();
        !            40: 
        !            41: my $plotcolors = ['#33ff00', 
        !            42:                   '#ff33cc', '#990000', '#aaaa66', '#663399', '#ff9933',
        !            43:                   '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
        !            44:                   ]; 
        !            45: 
        !            46: my @SubmitButtons = (
        !            47:                      { name => 'ProblemAnalyis',
        !            48:                        text => 'Analyze Problem Again' },
        !            49:                      { name => 'SelectAnother',
        !            50:                        text => 'Choose a different resource' },
        !            51:                      );
        !            52: 
        !            53: sub render_resource {
        !            54:     my ($resource) = @_;
        !            55:     ##
        !            56:     ## Render the problem
        !            57:     my $base;
        !            58:     ($base,undef) = ($resource->{'src'} =~ m|(.*/)[^/]*$|);
        !            59:     $base = "http://".$ENV{'SERVER_NAME'}.$base;
        !            60:     my $rendered_problem = 
        !            61:         &Apache::lonnet::ssi_body($resource->{'src'});
        !            62:     $rendered_problem =~ s/<\s*form\s*/<nop /g;
        !            63:     $rendered_problem =~ s|(<\s*/form\s*>)|<\/nop>|g;
        !            64:     return '<table bgcolor="ffffff"><tr><td>'.
        !            65:         '<base href="'.$base.'" />'.
        !            66:         $rendered_problem.
        !            67:         '</td></tr></table>';
        !            68: }
        !            69: 
        !            70: sub BuildSubmissionTimePage {
        !            71:     my ($r,$c)=@_;
        !            72:     $r->print('<h2>'.&mt('Submission Time Plots').'</h2>');
        !            73:     $r->print(&CreateInterface());
        !            74:     #
        !            75:     my @Students = @Apache::lonstatistics::Students;
        !            76:     #
        !            77:     if (@Students < 1) {
        !            78:         $r->print('<h2>There are no students in the sections selected</h2>');
        !            79:     }
        !            80:     #
        !            81:     &Apache::loncoursedata::clear_internal_caches();
        !            82:     if (exists($ENV{'form.ClearCache'}) || 
        !            83:         exists($ENV{'form.updatecaches'}) ||
        !            84:         (exists($ENV{'form.firstanalysis'}) &&
        !            85:          $ENV{'form.firstanalysis'} ne 'no')) {
        !            86:         &Apache::lonstatistics::Gather_Full_Student_Data($r);
        !            87:     }
        !            88:     if (! exists($ENV{'form.firstanalysis'})) {
        !            89:         $r->print('<input type="hidden" name="firstanalysis" value="yes" />');
        !            90:     } else {
        !            91:         $r->print('<input type="hidden" name="firstanalysis" value="no" />');
        !            92:     }
        !            93:     $r->rflush();
        !            94:     #
        !            95:     if (! exists($ENV{'form.problemchoice'}) ||
        !            96:         exists($ENV{'form.SelectAnother'})) {
        !            97:         $r->print('<input type="submit" name="" value="'.
        !            98:                   &mt('Graph Problem Submission Times').'" />');
        !            99:         $r->print('&nbsp;'x5);
        !           100:         $r->print('<h3>'.&mt('Please select a problem to analyze').'</h3>');
        !           101:         $r->print(&ProblemSelector());
        !           102:     } else {
        !           103:         foreach my $button (@SubmitButtons) {
        !           104:             $r->print('<input type="submit" name="'.$button->{'name'}.'" '.
        !           105:                       'value="'.&mt($button->{'text'}).'" />');
        !           106:             $r->print('&nbsp;'x5);
        !           107:         }
        !           108:         $r->print('<input type="hidden" name="problemchoice" value="'.
        !           109:                   $ENV{'form.problemchoice'}.'" />');
        !           110:         #
        !           111:         $r->print('<hr />');
        !           112:         #
        !           113:         my ($symb,$part) = &get_problem_symb(
        !           114:                   &Apache::lonnet::unescape($ENV{'form.problemchoice'}));
        !           115:         $r->rflush();
        !           116:         #
        !           117:         my $resource = &get_resource_from_symb($symb);
        !           118:         if (! defined($resource)) {
        !           119:             $r->print('resource is undefined');
        !           120:         } else {
        !           121:             $r->print('<h1>'.$resource->{'title'}.'</h1>');
        !           122:             $r->print('<h3>'.$resource->{'src'}.'</h3>');
        !           123:             $r->rflush();
        !           124:             $r->print(&render_resource($resource));
        !           125:             $r->rflush();
        !           126:             $r->print(&analyze_times($r,$resource,\@Students,$part));
        !           127:         }
        !           128:         $r->print('<hr />');
        !           129:     }
        !           130: }
        !           131: 
        !           132: #########################################################
        !           133: #########################################################
        !           134: ##
        !           135: ##                  Time Analysis
        !           136: ##
        !           137: #########################################################
        !           138: #########################################################
        !           139: sub get_week_start {
        !           140:     my ($randomtime) = @_;
        !           141:     my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = 
        !           142:         localtime($randomtime);
        !           143:     $randomtime -= $wday * 86400;
        !           144:     ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = 
        !           145:         localtime($randomtime);
        !           146:     my $week_start = &Time::Local::timelocal(0,0,0,$mday,$month,$year);
        !           147:     return $week_start;
        !           148: }
        !           149: 
        !           150: sub analyze_times {
        !           151:     my ($r,$resource,$students,$part) = @_;
        !           152:     my $html; # holds results of analysis
        !           153:     # Get the data
        !           154:     my $SubData = &Apache::loncoursedata::get_response_time_data
        !           155:         ($students,$resource->{'symb'},$part);
        !           156:     if (! defined($SubData) || ! ref($SubData)) {
        !           157:         $html.= '<h2>There is no submission data for this resource</h2>';
        !           158:         return $html;
        !           159:     }
        !           160:     my $NumSub = scalar(@{$SubData});
        !           161:     if (! @{$SubData}) {
        !           162:         $html.= '<h2>There is no submission data for this resource</h2>';
        !           163:         return $html;
        !           164:     }
        !           165:     # Process the data
        !           166:     #   Get first and last times
        !           167:     my $span = &get_time_from_row($SubData->[-1]) - 
        !           168:                &get_time_from_row($SubData->[0]);
        !           169:     if ($span == 0) {
        !           170:         $html.= '<h2>There is no submission data for this resource</h2>';
        !           171:         return $html;
        !           172:     }
        !           173:     #
        !           174:     my (undef,undef,undef,$mday,$month,$year,$wday,$yday,$isdst) = 
        !           175:         localtime(&get_time_from_row($SubData->[0]));
        !           176:     my $day_start = &Time::Local::timelocal(0,0,0,$mday,$month,$year);
        !           177:     my $start_day_of_week = $wday;
        !           178:     #
        !           179:     my @WeekDay = (qw/SUN MON TUE WED THU FRI SAT SUN/);
        !           180:     my @Month = (qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/);
        !           181:     #
        !           182:     my $cumulative_answers = 0;
        !           183:     #
        !           184:     my @Ydata;
        !           185:     my @AnsData;
        !           186:     my @Xlabel;
        !           187:     #
        !           188:     my $binsize = 3600; # seconds
        !           189:     my $bins_per_day = 86400/$binsize;
        !           190:     my $bincount = 0;
        !           191:     my $endtime = $day_start;
        !           192:     #
        !           193:     my $max;
        !           194:     foreach my $row (@$SubData) {
        !           195:         my $subtime = &get_time_from_row($row);
        !           196:         while ($subtime > $endtime && $endtime < time) {
        !           197:             # Create a new bin
        !           198:             $bincount++;
        !           199:             $Ydata[$bincount]=0;
        !           200:             $AnsData[$bincount]=$AnsData[$bincount-1];
        !           201:             $endtime += $binsize;
        !           202:             if ($bincount % (86400/$binsize) == 0) {
        !           203:                 $Xlabel[$bincount] = $WeekDay[$wday++];
        !           204:                 $wday %= 7;
        !           205:             } else {
        !           206:                 $Xlabel[$bincount] = '';
        !           207:             }
        !           208:         }
        !           209:         $Ydata[$bincount]++;
        !           210:         $max = $Ydata[$bincount] if ($max < $Ydata[$bincount]);
        !           211:         $AnsData[$bincount] += &successful_submission($row);
        !           212:         $cumulative_answers += &successful_submission($row);
        !           213:     }
        !           214:     foreach my $maximum (10,15,20,25,30,40,50,60,70,80,90,100,
        !           215:                           120,150,200,250,300,350,400,450,500,
        !           216:                           600,700,800,900,1000,1100,1200,1500,2000,
        !           217:                           2500,3000,4000,5000) {
        !           218:         if ($max < $maximum) {
        !           219:             $max = $maximum;
        !           220:             last;
        !           221:         }
        !           222:     }
        !           223:     while ($bincount % $bins_per_day != 0) {
        !           224:         $bincount++;
        !           225:         $Ydata[$bincount]=0;
        !           226:         $AnsData[$bincount]=$AnsData[$bincount-1];
        !           227:         $endtime += $binsize;
        !           228:         if ($bincount % (86400/$binsize) == 0) {
        !           229:             $Xlabel[$bincount] = $WeekDay[$wday];
        !           230:         } else {
        !           231:             $Xlabel[$bincount] = '';
        !           232:         }
        !           233:     }
        !           234: 
        !           235:     my $title = 'Number of Submissions and Number Correct';
        !           236:     my $xlabel;
        !           237:     (undef,undef,undef,$mday,$month,$year) = localtime($day_start);
        !           238:     $xlabel .= 'Sunday '.join(' ',($Month[$month],$mday,1900+$year)).' - ';
        !           239:     (undef,undef,undef,$mday,$month,$year) = localtime($endtime);
        !           240:     $xlabel .= 'Sunday '.join(' ',($Month[$month],$mday,1900+$year));
        !           241:     $html .= &Apache::loncommon::DrawXYYGraph($title,
        !           242:                                               $xlabel,
        !           243:                                               'Number of Submissions',
        !           244:                                               $plotcolors,
        !           245:                                               \@Xlabel,
        !           246:                                               \@Ydata,
        !           247:                                               0,$max,
        !           248:                                               \@AnsData,
        !           249:                                               0,scalar(@$students),
        !           250:                                               (xskip => $bins_per_day,
        !           251:                                                x_ticks => $bins_per_day,
        !           252:                                                x_tick_offset => $bins_per_day,
        !           253:                                                width => 50+2*$bincount)
        !           254:                                               );
        !           255:     $html .= '<br />';
        !           256:     return $html;
        !           257: }
        !           258: 
        !           259: sub successful_submission {
        !           260:     my ($row) = @_;
        !           261:     if (ref($row) eq 'ARRAY') {
        !           262:         return $row->[1];
        !           263:     }
        !           264:     return undef;
        !           265:     return 0;
        !           266: }
        !           267: 
        !           268: sub get_time_from_row {
        !           269:     my ($row) = @_;
        !           270:     if (ref($row) eq 'ARRAY') {
        !           271:         return $row->[3];
        !           272:     } 
        !           273:     return undef;
        !           274: }
        !           275: 
        !           276: sub get_tries_from_row {
        !           277:     my ($row) = @_;
        !           278:     if (ref($row) eq 'ARRAY') {
        !           279:         return $row->[2];
        !           280:     }
        !           281:     return undef;
        !           282: }
        !           283: 
        !           284: sub Process_Row {
        !           285:     my ($row) = @_;
        !           286:     my %RowData;
        !           287:     my ($student_id,$award,$tries,$time) = @$row;
        !           288:     return %RowData;
        !           289: }
        !           290: 
        !           291: #########################################################
        !           292: #########################################################
        !           293: ##
        !           294: ##   Generic Interface Routines
        !           295: ##
        !           296: #########################################################
        !           297: #########################################################
        !           298: sub CreateInterface {
        !           299:     ##
        !           300:     ## Environment variable initialization
        !           301:     if (! exists$ENV{'form.AnalyzeOver'}) {
        !           302:         $ENV{'form.AnalyzeOver'} = 'Tries';
        !           303:     }
        !           304:     ##
        !           305:     ## Build the menu
        !           306:     my $Str = '';
        !           307:     $Str .= '<table cellspacing="5">'."\n";
        !           308:     $Str .= '<tr>';
        !           309:     $Str .= '<td align="center"><b>'.&mt('Sections').'</b></td>';
        !           310:     $Str .= '<td align="center"><b>'.&mt('Enrollment Status').'</b></td>';
        !           311:     $Str .= '<td align="center">&nbsp;</td>';
        !           312:     $Str .= '</tr>'."\n";
        !           313:     ##
        !           314:     ## 
        !           315:     $Str .= '<tr><td align="center">'."\n";
        !           316:     $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
        !           317:     $Str .= '</td>';
        !           318:     #
        !           319:     $Str .= '<td align="center">';
        !           320:     $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5);
        !           321:     $Str .= '</td>';
        !           322:     #
        !           323:     my $only_seq_with_assessments = sub { 
        !           324:         my $s=shift;
        !           325:         if ($s->{'num_assess'} < 1) { 
        !           326:             return 0;
        !           327:         } else { 
        !           328:             return 1;
        !           329:         }
        !           330:     };
        !           331:     &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
        !           332:                                               $only_seq_with_assessments);
        !           333:     ##
        !           334:     ##
        !           335:     $Str .= '</tr>'."\n";
        !           336:     $Str .= '</table>'."\n";
        !           337:     return $Str;
        !           338: }
        !           339: 
        !           340: sub ProblemSelector {
        !           341:     my $Str;
        !           342:     $Str = "<table>\n";
        !           343:     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
        !           344:         next if ($seq->{'num_assess'}<1);
        !           345:         my $seq_str = '';
        !           346:         foreach my $res (@{$seq->{'contents'}}) {
        !           347:             next if ($res->{'type'} ne 'assessment');
        !           348:             if (@{$res->{'parts'}} == 1) {
        !           349:                 my $value = &Apache::lonnet::escape($res->{'symb'}.':'.
        !           350:                                                     $res->{'parts'}->[0]);
        !           351:                 my $checked;
        !           352:                 if ($ENV{'form.problemchoice'} eq $value) {
        !           353:                     $checked = 'checked ';
        !           354:                 }
        !           355:                 $seq_str .= '<tr><td>'.
        !           356:   '<input type="radio" name="problemchoice" value="'.$value.'" '.$checked.'/>'.
        !           357:   '</td><td>'.
        !           358:   '<a href="'.$res->{'src'}.'">'.$res->{'title'}.'</a> ';
        !           359:             } else {
        !           360:                 $seq_str .= '<tr><td>'.
        !           361:                     '&nbsp;'.'</td><td>'.
        !           362:                     '<a href="'.$res->{'src'}.'">'.$res->{'title'}.'</a>'.
        !           363:                     "</td></tr>\n";
        !           364:                 foreach my $part (@{$res->{'parts'}}) {
        !           365:                     my $value = &Apache::lonnet::escape
        !           366:                                                ($res->{'symb'}.':'.$part);
        !           367:                     my $checked;
        !           368:                     if ($ENV{'form.problemchoice'} eq $value) {
        !           369:                         $checked = 'checked ';
        !           370:                     }
        !           371:                     $seq_str .= '<tr><td>'.
        !           372:   '<input type="radio" name="problemchoice" value="'.$value.'" '.$checked.'/>'.
        !           373:   '</td><td>'.('&nbsp;'x5).'part '.$part."</td></tr>\n";
        !           374:                 }
        !           375:             }
        !           376:         }
        !           377:         if ($seq_str ne '') {
        !           378:             $Str .= '<tr><td>&nbsp</td><td><b>'.$seq->{'title'}.'</b></td>'.
        !           379:                 "</tr>\n".$seq_str;
        !           380:         }
        !           381:     }
        !           382:     $Str .= "</table>\n";
        !           383:     return $Str;
        !           384: }
        !           385: 
        !           386: #########################################################
        !           387: #########################################################
        !           388: ##
        !           389: ##      Misc functions (ought to be put in a module)
        !           390: ##
        !           391: #########################################################
        !           392: #########################################################
        !           393: sub get_problem_symb {
        !           394:     my $problemstring = shift();
        !           395:     my ($symb,$partid) = ($problemstring=~ /^(.*):([^:]*)$/);
        !           396:     return ($symb,$partid);
        !           397: }
        !           398: 
        !           399: sub get_resource_from_symb {
        !           400:     my ($symb) = @_;
        !           401:     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
        !           402:         foreach my $res (@{$seq->{'contents'}}) {
        !           403:             if ($res->{'symb'} eq $symb) {
        !           404:                 return $res;
        !           405:             }
        !           406:         }
        !           407:     }
        !           408:     return undef;
        !           409: }
        !           410: 
        !           411: 1;
        !           412: 
        !           413: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>