fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2010-07-29 05:56 am

[dw-free] Create a graphical front-end for the statistics system

[commit: http://hg.dwscoalition.org/dw-free/rev/a71463d5d873]

http://bugs.dwscoalition.org/show_bug.cgi?id=2699

Add module that creates graphs for the statistics system; add a script with
usage examples. Available graphs are: pie charts, bar charts, bar chart with
multiple bars, line graphs.

Patch by [personal profile] anarres.

Files modified:
  • bin/dev/graphs_usage.pl
  • cgi-bin/DW/Graphs.pm
  • etc/clrs.txt
--------------------------------------------------------------------------------
diff -r be9772bf3332 -r a71463d5d873 bin/dev/graphs_usage.pl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/dev/graphs_usage.pl	Wed Jul 28 22:56:28 2010 -0700
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+#
+# dw/bin/dev/graphs_usage.pl - Graphs usage examples
+#
+# Authors:
+#      Anarres <anarres@dreamwidth.org>
+#
+# Copyright (c) 2010 by Dreamwidth Studios, LLC.
+#
+# Gives examples of usage of the DW::Graphs module to make pie, bar, and line
+# graphs. This script is only for the purpose of showing how the Graphs module
+# works, normally the Graphs module would be used by graph image controller modules
+# such as DW::Controller::PaidAccountsGraph, not by a standalone script.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
+use lib "$ENV{LJHOME}/cgi-bin";
+use DW::Graphs;
+use strict;
+use warnings;
+
+# Generate a pie chart pie.png ------------------------------------------------>
+my $pie_ref = {
+    "label 1" => 1,
+    "label 2" => 0.05,
+    "label 3" => 0.07,
+    "label 4" => 1.5,
+    "label 5" => 0.12,
+};
+
+# Make the graph
+my $gd = DW::Graphs::pie( $pie_ref );
+
+# Print the graph to a file
+open(IMG, '>pie.png') or die $!;
+binmode IMG;
+print IMG $gd->png;
+
+
+# Generate a bar chart bar.png ------------------------------------------------>
+my $bar_ref = [ 13.377, 15.9, 145.67788, 123.1111, 0.1, 44.03455, 33.3, 43, 123 ];
+
+# Labels - one label per bar. If labels are not wanted pass empty strings.
+# Optinally put "\n" in front of every 2nd label to stop them crowding each-other.
+my $bar_labels = [ ( "label 1", "\nlabel 2", "label 3", "\nlabel 4", "label 5",
+    "\nlabel 6", "label 7", "\nlabel 8", "label 9" ) ];
+
+# Make the graph
+my $bar_gd = DW::Graphs::bar( $bar_ref, $bar_labels, 'x-axis label', 'y-axis label' );
+
+# Print the graph to a file
+open(IMG, '>bar.png') or die $!;
+binmode IMG;
+print IMG $bar_gd->png;
+
+
+# Generate a bar chart bar2.png with two datasets ----------------------------->
+
+# You can have any number of datasets - here there are two
+my @values1 = ( 7243, 15901, 26188 );
+my @values2 = ( 4243, 12901, 11188 );
+
+# Dataset names to distinguish the datasets, used in the legend. The number
+# of dataset names must be the same as the number of datasets!
+my $names_ref = [ ( "Dataset 1",  "Dataset 2" ) ];
+
+# labels - one label per bar. The number of labels must be the same as the
+# number of values per dataset. If labels are not wanted pass empty strings.
+my @bar2_labels = ( "Bar 1", "Bar 2", "Bar 3" );
+
+# Package the input
+my $bar2_input = [ [@bar2_labels], [@values1], [@values2] ];
+
+# Make the graph
+my $bar2_gd = DW::Graphs::bar2( $bar2_input, 'x-axis label', 'y-axis label', $names_ref);
+
+# Print the graph to a file
+open(IMG, '>bar2.png') or die $!;
+binmode IMG;
+print IMG $bar2_gd->png;
+
+
+# Generate a line graph lines.png --------------------------------------------->
+
+# Define labels to go along the horizontal axis under the graph.
+# If you don't want labels, use empty strings
+my @line_labels = ( "1st","2nd","3rd","4th","5th","6th","7th", "8th" );
+
+# Define the datasets - each dataset will form one line on the graph
+# Each dataset should have the same length as the number of labels
+my @dataset1 = qw( 1900 2035 2078 2140 2141 2200 2460 2470 2576 );
+my @dataset2 = qw( 871 996 990 1058 1102 1162 1105 1150 );
+my @dataset3 = qw( 200 360 370 471 496 690 758 802 );
+
+# Names for the datasets, to go in the graph legend
+my $line_names = [ "1st dataset", "2nd dataset", "3rd dataset" ];
+
+# Put the data in a format that the Graphs module can deal with
+my $line_ref = [ [@line_labels], [@dataset1], [@dataset2], [@dataset3] ];
+
+# Make the graph
+my $line_gd = DW::Graphs::lines( $line_ref, 'x-axis label', 'y-axis label', 
+   $line_names );
+
+# Print the graph to a file
+open(IMG, '>lines.png') or die $!;
+binmode IMG;
+print IMG $line_gd->png;
diff -r be9772bf3332 -r a71463d5d873 cgi-bin/DW/Graphs.pm
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cgi-bin/DW/Graphs.pm	Wed Jul 28 22:56:28 2010 -0700
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+#
+# DW::Graphs - creates graphs for the statistics system
+#
+# Authors:
+#      Anarres <anarres@dreamwidth.org>
+#
+# Copyright (c) 2010 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
+package DW::Graphs;
+
+use strict;
+use warnings;
+use lib "$ENV{LJHOME}/cgi-bin";
+require 'ljlib.pl'; 
+use GD::Graph;
+use GD::Graph::bars;
+use GD::Graph::hbars;
+use GD::Graph::pie;
+use GD::Graph::lines;
+use GD::Text;
+use GD::Graph::colour;
+GD::Graph::colour::read_rgb("$LJ::HOME/etc/clrs.txt")
+    or die "cannot read colours";
+
+# Generates a pie chart. The argument is a hashref of labels and values.
+# Returns graph object $gd which can be printed with the command: print $gd->png;
+# See ~/dw/bin/dev/graphs_usage.pl for more detailed usage information.
+sub pie {
+    my ( $pie_ref ) = @_;
+
+    # Sort the key-value pairs of %$pie_ref by value:
+    # @pie_labels is the keys and @pie_values is the values
+    my @pie_labels = sort { $pie_ref->{$a} cmp $pie_ref->{$b} } keys %$pie_ref;
+    my @pie_values = map { $pie_ref->{$_} } @pie_labels;
+
+    # Package the data in a way that makes GD::Graph happy
+    my $pie = [ [@pie_labels], [@pie_values] ];
+
+    # Create graph object
+    my $graph = GD::Graph::pie->new( 300, 300 );
+    $graph->set(
+        transparent    => 0,      # Set this to 1 for transparent background
+        accentclr      => 'nearly_white', 
+        start_angle    => 90,     # Angle of first slice of pie, 0 = 6 o'clock
+        suppress_angle => 5,      # Smaller slices than this have no labels
+        bgclr          => 'background',
+        dclrs          => [ qw( pie_blue pie_orange pie_bluegreen pie_green
+                           pie_yellow pie_pink ) ], 
+        labelclr       => '#000000',
+        valuesclr      => '#000000',
+        textclr        => 'dw_red',
+        '3d'           => 0,
+    ) or die $graph->error;
+
+    # FIXME: make the pathnames and font sizes configurable
+    $graph->set_title_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 14);
+    $graph->set_value_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+
+    my $gd = $graph->plot( $pie ) or die $graph->error;
+    return $gd;
+} 
+
+# Generates a bar chart. Arguments: a ref to an array of values, a ref to an
+# array of labels, title, x-axis label, y-axis label. # Returns graph object
+# $gd which can be printed with the command: print $gd->png; see 
+# graphs_usage.pl for more detailed usage information.
+sub bar {
+    my ( $values_ref, $labels_ref, $xlabel, $ylabel ) = @_;
+
+    # Package the input as required by GD Graph
+    my $input_ref = [ $labels_ref, $values_ref ];
+
+    # Create graph object
+    my $graph = GD::Graph::bars->new(500, 350);
+
+    # Graph settings
+      $graph->set( 
+            x_label         => "\n$xlabel",
+            y_label         => $ylabel,
+            show_values    => 1,
+            values_space   => 1, # Pixels between top of bar and value above
+            b_margin       => 20, # Bottom margin (makes space for labels)
+            bar_spacing    => 50, # Higher value = thinner bars
+
+            bgclr          => 'background',
+            fgclr          => 'white',
+            boxclr         => '#f4eedc', # Shaded-in background
+            long_ticks     => 1,         # Background grid lines
+            accentclr      => 'lgray',   # Colour of grid lines
+            accent_treshold => 500,      # Get rid of outline around bars
+
+            labelclr       => '#000000',
+            axislabelclr   => '#000000',
+            legendclr      => '#000000',
+            valuesclr      => '#000000',
+            textclr        => 'dw_red',
+
+            transparent    => 0,         # 1 for transparent background
+            dclrs          => [ qw( pie_blue pie_orange pie_bluegreen pie_green
+                               pie_yellow pie_pink ) ],
+      ) or die $graph->error;
+
+    # FIXME: make the pathnames and font sizes configurable
+    $graph->set_title_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 14);
+    $graph->set_x_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_y_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_x_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_y_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_values_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+
+    # Make the graph
+     my $gd = $graph->plot( $input_ref ) or die $graph->error;
+    return $gd;
+} 
+
+# Generates a bar chart with two or more sets of data represented by each bar.
+# Arguments: a reference containing labels and datasets, x-axis label,
+# y-axis label, ref to array of names for datasets. Returns graph object 
+# $gd which can be printed with the command: print $gd->png; see 
+# ~/dw/bin/dev/graphs_usage.pl for more detailed usage information.
+sub bar2 {
+    my ( $ref, $xlabel, $ylabel, $names_ref ) = @_;
+
+    # Create graph object
+    my $graph = GD::Graph::bars->new(500, 350);
+
+    # Graph settings
+    $graph->set( 
+        x_label         => "\n$xlabel",
+        y_label         => $ylabel,
+        show_values    => 1,
+        values_space   => 1, # Pixels between top of bar and value above
+        b_margin       => 20, # Bottom margin (makes space for labels)
+        bar_spacing    => 50, # Higher value = thinner bars
+        legend_placement => 'RC',      # Right centre
+        cumulate => 'true',  # Put the two datasets in one bar
+
+        shadowclr      => 'background',
+        bgclr          => 'background',
+        fgclr          => 'white',
+        boxclr         => '#f4eedc', # Shaded-in background 
+        long_ticks     => 1,         # Background grid lines
+        accentclr      => 'white',   # Colour of grid lines
+        transparent    => 0,         # 1 for transparent background
+        #accent_treshold => 500,      # Get rid of outline around bars
+
+        labelclr       => '#000000',
+        axislabelclr   => '#000000',
+        legendclr      => '#000000',
+        valuesclr      => '#000000',
+        textclr        => 'dw_red',
+
+        dclrs          => [ qw( pie_blue pie_orange pie_bluegreen pie_green
+                           pie_yellow pie_pink ) ],
+    ) or die $graph->error;
+
+    # FIXME: make the pathnames and font sizes configurable
+    $graph->set_title_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 14);
+    $graph->set_x_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_y_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_x_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_y_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_values_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_legend_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+
+    # Set legend
+    $graph->set_legend( @$names_ref );
+
+    # Make the graph
+    my $gd = $graph->plot( $ref ) or die $graph->error;
+    return $gd;
+}
+
+# Generates a line graph. Arguments: a reference containing labels and datasets,
+# x-axis label, y-axis label, ref to array of names for datasets. Returns
+# graph object $gd which can be printed with the command: print $gd->png; see
+# ~/dw/bin/dev/graphs_usage.pl for more detailed usage information.
+sub lines {
+    my ( $data_ref, $xlabel, $ylabel, $data_names ) = @_;
+
+    # Create new Graph object $graph 750px by 320 px
+    my $graph = GD::Graph::lines->new(750, 320);
+
+    # Graph settings:
+    $graph->set( 
+        x_label       => $xlabel,
+        y_label       => $ylabel,
+        show_values   => 0,
+        transparent   => 0,            # Set this to 1 for transparent background
+        line_width    => 1,
+        long_ticks    => 1,            # Background grid lines
+        line_width    => 4,            # Line width in pixels
+        legend_placement => 'RC',      # Right centre
+
+        bgclr         => 'background',
+        fgclr         => 'white',
+        boxclr        => '#f4eedc',    # Shaded-in background colour
+        accentclr     => 'lgray',
+
+        labelclr       => '#000000',
+        axislabelclr   => '#000000',
+        legendclr      => '#000000',
+        valuesclr      => '#000000',
+        textclr        => 'dw_red',
+        dclrs                 => [ qw( solid0 solid1 solid2 solid3 solid4 ) ],
+        ) or die $graph->error;
+
+    $graph->set( line_types => [1, 2, 3, 4] ); # 1:solid 2:dash 3:dot 4:dot-dash
+
+    # FIXME: make the pathnames and font sizes configurable
+    $graph->set_title_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 14);
+    $graph->set_legend_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_x_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_y_label_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 12);
+    $graph->set_x_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_y_axis_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+    $graph->set_values_font("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 10);
+
+    # Set legend
+    $graph->set_legend( @$data_names );
+
+    # Make the plot
+    my $gd = $graph->plot( $data_ref ) or die $graph->error;
+    return $gd;
+}
+1;
diff -r be9772bf3332 -r a71463d5d873 etc/clrs.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/clrs.txt	Wed Jul 28 22:56:28 2010 -0700
@@ -0,0 +1,32 @@
+# dw/etc/clrs.txt
+#
+# Defines colours to be used by DW::Graphs
+#
+# Authors:
+#      Anarres <anarres@dreamwidth.org> 
+#
+# Copyright (c) 2010 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
+# Solid colours 
+90  132 0         solid0
+146 13  27        solid1
+17  6   82        solid2
+229 187 27        solid3
+13  61  37        solid4
+
+# Colours for pie charts
+126 175 210      pie_blue
+243 151 62       pie_orange
+119 203 162      pie_bluegreen
+165 198 64       pie_green
+237 211 68       pie_yellow
+215 139 169      pie_pink
+
+# Other
+247 247 247      background
+197 53  60       dw_red
+248 248 248      nearly_white
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org