[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
anarres.
Files modified:
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]](https://www.dreamwidth.org/img/silk/identity/user.png)
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 --------------------------------------------------------------------------------