File:  [LON-CAPA] / loncom / interface / statistics / loncorrectproblemplot.pm
Revision 1.28: download - view: text, annotated - select for diffs
Mon May 7 10:12:42 2012 UTC (12 years ago) by goltermann
Branches: MAIN
CVS tags: version_2_12_X, version_2_11_X, HEAD
added &mt() for range/count table header

# The LearningOnline Network with CAPA
#
# $Id: loncorrectproblemplot.pm,v 1.28 2012/05/07 10:12:42 goltermann Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#

package Apache::loncorrectproblemplot;

use strict;
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::lonquickgrades();
use Apache::loncoursedata();
use Apache::lonstatistics;
use Apache::lonstathelpers;
use Apache::lonlocal;

my @SubmitButtons = (
                     { name => 'CreatePlot',
                       text => 'Create Plot' },
                     );

#########################################################
#########################################################

=pod

=item &BuildCorrectProblemsPage

Entry point from lonstatistics to the correct problems plot page.

=cut

#########################################################
#########################################################

sub BuildCorrectProblemsPage {
    my ($r,$c)=@_;
    #
    my %Saveable_Parameters = ('Status' => 'scalar',
                               'Section' => 'array',
                               'Groups' => 'array');
    &Apache::loncommon::store_course_settings('correct_problems_plot',
                                              \%Saveable_Parameters);
    &Apache::loncommon::restore_course_settings('correct_problems_plot',
                                                \%Saveable_Parameters);
    #
    &Apache::lonstatistics::PrepareClasslist();    
    
    $r->print(&Apache::lonhtmlcommon::breadcrumbs('Correct Problems Plot'));
    &Apache::lonquickgrades::startGradeScreen($r,'statistics');
    #
    $r->print(&CreateInterface());
    #
    my @Students = @Apache::lonstatistics::Students;
    #
    if (@Students < 1) {
        $r->print('<h2>'.
                  &mt('There are no students in the sections/groups selected').
                  '</h2>');
    }
    #
    my @CacheButtonHTML = 
        &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status');
    foreach my $button (@SubmitButtons) {
        $r->print('<input type="submit" name="'.$button->{'name'}.'" '.
                  'value="'.&mt($button->{'text'}).'" />');
        $r->print('&nbsp;'x5);
    }
    foreach my $html (@CacheButtonHTML) {
        $r->print($html.('&nbsp;'x5));
    }
    $r->rflush();
    #
    # Determine which problem symbs we are to sum over
    if (exists($env{'form.CreatePlot'})) {
        my @ProblemSymbs;
        my $total_weights = 0;
        my $title = '';
        my @maps = &Apache::lonstatistics::get_selected_maps('Maps');
        my ($navmap,@sequences) =
            &Apache::lonstatistics::selected_sequences_with_assessments();
        if ($maps[0] ne 'all') {
            foreach my $seq (@sequences) {
                if ($title eq '') {
                    $title = $seq->compTitle;
                } else {
                    $title = 'Multiple Sequences';
                }
            }
        } else {
            $title = 'All Problems';
        }
        foreach my $seq (@sequences) {
            my @resources = 
                &Apache::lonstathelpers::get_resources($navmap,$seq);
            foreach my $res (@resources) {
                foreach my $partid (@{$res->parts}) {
                    push(@ProblemSymbs,{symb=>$res->symb,
                                        part=>$partid});
                    $total_weights += 
                        &Apache::lonnet::EXT('resource.'.$partid.'.weight',
                                             $res->symb,
                                             undef,undef,undef);
                }
            }
        }
        $r->print('<p>'.
                  &Apache::lonstatistics::section_and_enrollment_description().
                  '</p>');
        my ($starttime,$endtime) = &Apache::lonstathelpers::get_time_limits();
        if (defined($starttime) || defined($endtime)) {
            # Inform the user what the time limits on the data are.
            $r->print(&mt('Statistics on submissions from [_1] to [_2]',
                          &Apache::lonlocal::locallocaltime($starttime),
                          &Apache::lonlocal::locallocaltime($endtime)));
        }
        &Apache::loncoursedata::populate_weight_table();
        my $score_data = &Apache::loncoursedata::get_student_scores
            ([&Apache::lonstatistics::get_selected_sections()],
             [&Apache::lonstatistics::get_selected_groups()],
             \@ProblemSymbs,
             $Apache::lonstatistics::enrollment_status,undef,
             $starttime,$endtime);
        $r->print(&AnalyzeScoreData($score_data,$title,$total_weights));
    } else {
        $r->print('<p>'.&mt('Make a sequence selection from the "Sequences and Folders" menu and hit "Create Plot" to begin').'</p>');
    }
    return;
}

#########################################################
#########################################################

=pod

=item & AnalyzeScoreData($score_data)

Analyze the result of &Apache::loncoursedata::get_student_scores() and
return html with a plot of the data and a table of the values and bins.

=cut

#########################################################
#########################################################
sub AnalyzeScoreData {
    my ($score_data,$title,$maximum) = @_;
    #
    # Basic check first
    if (ref($score_data) ne 'ARRAY' || @$score_data < 1) {
        return '<p class="LC_warning">'.&mt('There is no data to plot').'</p>';
    }
    #
    # Determine which bins to use
    my $lowest  = $score_data->[0]->[0];
    $lowest = 0;
    my $highest = $score_data->[-1]->[0];
    my $binsize = 1;
    if ($highest > 50) { $binsize = 2; }
    if ($highest > 100) { $binsize = 5; }
    if ($highest > 200) { $binsize = 10; }
    if ($highest > 500) { $binsize = 20; }
    if ($highest > 1000) { $binsize = 50; }
    if ($highest > 2000) { $binsize = 100; }
    #
    # Get the data into the bins (destroying $score_data in the process)
    my @Bins = &bin_data($score_data,$binsize,$lowest,$highest);
    my @Xdata; my @Ydata; my $max;
    my $Str = 
        '<p>'.
        &mt('Problem weights do not reflect individual student settings.')
        .'</p>'.
        &Apache::loncommon::start_data_table().
        &Apache::loncommon::start_data_table_header_row().
        '<th>'.&mt('Range').'</th><th>'.&mt('Count').'</th>'.
        &Apache::loncommon::end_data_table_header_row();
    my $sum = 0;
    while (my $bin = shift(@Bins)) {
        push (@Xdata,$bin->{'start'});
        push (@Ydata,$bin->{'count'});
        $sum += $bin->{'count'};
        if ($bin->{'count'} > $max) {
            $max = $bin->{'count'};
        }
        $Str.= &Apache::loncommon::start_data_table_row().
            '<td>'.$bin->{'start'}.' - '.$bin->{'end'}.'</td>'.
            '<td>'.$bin->{'count'}.'</td>'.
            &Apache::loncommon::end_data_table_row().'<br>';
    }
    # scale max to an integer.
    $max = 5*(int($max/5)+1);
    $Str .= &Apache::loncommon::end_data_table()."<br />\n";
    $title = &HTML::Entities::decode($title);
    $Str = "\n<p>".
        &Apache::loncommon::DrawBarGraph($title.' ('.$sum.' students)',
                              'Correct Problems (max possible = '.$maximum.')',
                                         'Number of students',
                                         $max,undef, # colors
                                         \@Xdata,\@Ydata).
                                         "\n<br />\n".$Str;
    $Str .= '</p>'."\n";
    return $Str;                                               
}


#########################################################
#########################################################

=pod

=item &bin_data($data,$binsize,$startbin,$endbin)

Note: This routine destroys the array of data passed to it.

Inputs: $data: array reference - the contents of @$data must
        be arrays with x and y data.  $data = [ [x1,y1],[x2,y2],...];
        $binsize: Width of bins to put data in
        $startbin: the starting bin.
        $endbin: the ending bin.
Returns: Array of Bins.  Each bin is a hash reference with the following
         keys: 'start', 'count', and 'end'.

=cut

#########################################################
#########################################################
sub bin_data {
    my ($data,$binsize,$startbin,$endbin)=@_;
    return () if (! defined($data) || ref($data) ne 'ARRAY');
    #
    # Determine bin geometry
    my $binstart = $startbin;
    my $binend = $startbin+$binsize;
    # put the data into bins
    my @Bins;
    my $count=0;
    my $idx=0;
    while ($idx < scalar(@$data) && ($endbin-$binend + $binsize)>=0) {
        my $dataset = $data->[$idx++];
        my ($x,$y) = @{$dataset};
        while ($x > ($binend-.001)) {
            # store the old data
            push (@Bins,{ start => $binstart,
                          count => $count,
                          end   => $binend });
            # start counting again
            $binstart += $binsize;
            $binend += $binsize;
            $count = 0;
        }
        $count+=$y;
    }
    if ($count > 0) {
        push (@Bins,{ start => $binstart,
                      count => $count,
                      end   => $binend });
    }
    return @Bins;
}

#########################################################
#########################################################

=pod

=item &CreateInterface

Inputs: none.

Returns: HTML for the correct problems plot interface.

=cut

#########################################################
#########################################################
sub CreateInterface {
    ##
    ## Environment variable initialization
    my $Str;
    $Str .= '<p>';
    #
    $Str .= &Apache::loncommon::start_data_table();
    $Str .= &Apache::loncommon::start_data_table_header_row();
    $Str .= '<th>'.&mt('Sections').'</th>';
    $Str .= '<th>'.&mt('Groups').'</th>';
    $Str .= '<th>'.&mt('Access Status').'</th>';
    $Str .= '<th>'.&mt('Sequences and Folders').'</th>';
    $Str .= '<th>'.&mt('Time Period').'</th>';
    $Str .= &Apache::loncommon::end_data_table_header_row();
    #
    $Str .= &Apache::loncommon::start_data_table_row();
    $Str .= '<td align="center" valign="top">'."\n";
    $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
    $Str .= '</td>';
    #
    $Str .= '<td align="center" valign="top">'."\n";
    $Str .= &Apache::lonstatistics::GroupSelect('Group','multiple',5);
    $Str .= '</td>';
    $Str .= '<td align="center" valign="top">';
    $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5);
    $Str .= '</td>'."\n";
    #
    $Str .= '<td align="center" valign="top">'."\n";
    $Str .= &Apache::lonstatistics::map_select('Maps','multiple,all',5);
    $Str .= '</td>';
    #
    $Str .= '<td align="center" valign="top">'."\n";
    $Str .= &Apache::lonstathelpers::limit_by_time_form();
    $Str .= '</td>';
    #
    $Str .= &Apache::loncommon::end_data_table_row();
    $Str .= &Apache::loncommon::end_data_table();
    ##
    return $Str;
}

1;

__END__

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