File Coverage

blib/lib/Geo/Cartogram.pm
Criterion Covered Total %
statement 9 43 20.9
branch 0 8 0.0
condition 0 6 0.0
subroutine 3 8 37.5
pod 3 4 75.0
total 15 69 21.7


line stmt bran cond sub pod time code
1             package Geo::Cartogram;
2              
3 1     1   41797 use 5.008008;
  1         4  
  1         43  
4 1     1   6 use strict;
  1         2  
  1         37  
5              
6 1     1   3294 use Geo::ShapeFile;
  1         337813  
  1         841  
7              
8             our $VERSION = '0.01';
9              
10             =head1 NAME
11              
12             Geo::Cartogram - Perl extension for generating cartograms
13              
14             =head1 SYNOPSIS
15              
16             use Geo::Cartogram;
17              
18             my $cart = Geo::Cartogram->new('world.shp');
19              
20             # Generates map.gen file as expected by cartogram program
21             $cart->generateMapFile('cartogram/map.gen');
22              
23             # Generate census.dat file, this will result in homogeneous cartogram
24             $cart->generateDataFile('cartogram/census.dat');
25              
26             # Use subroutine to get region atribute
27             my $getPopulation = sub {
28             my $country = shift;
29             return $mylib->getPopulation($country->{name});
30             };
31              
32             $cart->generateDataFile('cartogram/census.dat', $getPopulation);
33              
34             chdir('cartogram');
35             system('./cartogram');
36              
37             =head1 DESCRIPTION
38              
39             A cartogram is a map in which the sizes of the enumeration units have been rescaled according
40             to an attribute they posses rather than their actual size.
41              
42             Resizing a map's regions in a way that keeps the map recognizable is a difficult problem. Michael Gastner
43             proposed a method and made available a C program to generate cartograms. By now, Geo::Cartogram simply
44             takes a map in ESRI's shapefile format (.shp) and a user-defined function to generate the files needed for
45             Gastner's program to run. See "CARTOGRAM PROGRAM" below.
46              
47             =head1 CONSTRUCTOR
48              
49             =over 4
50              
51             =item new($shapeFile)
52              
53             Receives the path of file in ESRI's shapefile format. The ".shp" is optional, there must also be the .dbf and .shx files
54             in same dir.
55              
56             =cut
57              
58             sub new {
59 0     0 1   my $pack = shift;
60 0           my $fileName = shift;
61              
62 0           $fileName =~ s/(\.shp)?$/.shp/i;
63              
64 0 0         my $shapefile = new Geo::ShapeFile($fileName)
65             or return undef;
66              
67 0           bless { SHAPE => $shapefile }, $pack;
68             }
69              
70 0     0 0   sub shape { shift->{SHAPE} }
71              
72             =pod
73              
74             =back
75              
76             =head1 METHODS
77              
78             =over 4
79              
80             =item generateMapFile($mapfile);
81              
82             This will read map polygons information from shapefile and write $mapfile in format expected by cartogram
83             program. The file format is the same as exported by ArcInfo program. You probably want to call this file map.gen.
84              
85             =cut
86              
87             sub generateMapFile {
88 0     0 1   my $self = shift;
89 0   0       my $mapfile = shift || 'map.gen';
90              
91 0 0         open GEN, ">$mapfile" or die "Can't open $mapfile for writing: $!";
92              
93 0           foreach my $shapeId (1 .. $self->shape->shapes()) {
94 0           my $shape = $self->shape->get_shp_record($shapeId);
95              
96 0           foreach my $partId (1 .. $shape->num_parts()) {
97 0           print GEN $shapeId, "\n";
98              
99 0           my @segments = $shape->get_segments($partId);
100              
101 0           foreach my $segment (@segments) {
102 0           print GEN $segment->[0]->{X}, " ", $segment->[0]->{Y}, "\n";
103             }
104 0           my $segment = pop @segments;
105 0           print GEN $segment->[1]->{X}, " ", $segment->[1]->{Y}, "\n";
106 0           print GEN "END\n";
107             }
108             }
109              
110 0           print GEN "END\n";
111              
112 0           close GEN;
113              
114 0           1;
115             }
116              
117             =pod
118              
119             =item generateDataFile($datafile, [$attributeFunction]);
120              
121             This will generate a data file containing the relative size of each region of the map and write it to
122             $datafile, which cartogram program expects to be called census.dat.
123              
124             $attributeFunction is a subroutine reference that receives a hashref containing all information from a
125             map region (according to DBF file that comes with shapefile) and returns its relative size. If no
126             function is given, all regions will be drawn with equal size.
127              
128             =cut
129              
130             sub generateDataFile {
131 0     0 1   my $self = shift;
132 0   0       my $datafile = shift || 'census.dat';
133 0   0 0     my $sizeSub = shift || sub { 1 };
  0            
134              
135 0 0         ref($sizeSub) eq 'CODE' or die "generateDataFile expects a subroutine as second parameter";
136              
137 0 0         open DAT, ">$datafile" or die "Can't open $datafile for writing: $!";
138            
139 0           foreach my $shapeId (1 .. $self->shape->shapes()) {
140 0           my $regionData = $self->shape->get_dbf_record($shapeId);
141              
142 0           my $size = &$sizeSub($regionData);
143              
144 0           print DAT "$shapeId $size\n";
145             }
146 0           close DAT;
147              
148 0           1;
149             }
150              
151             =pod
152              
153             =back
154              
155             =head1 CARTOGRAM PROGRAM
156              
157             cartogram.c was written by Michael Gastner and is available for download at http://www.santafe.edu/%7Emgastner/.
158              
159             Its license is not clearly stated, but the author let you use it and doesn't say any restriction, just ask you
160             to acknowledge the use of his code and its first publication as below in any output of the code:
161            
162             "Generating population density-equalizing maps", Michael T. Gastner and M. E. J. Newman,
163             Proceedings of the National Academy of Sciences of the United States of America, vol. 101, pp. 7499-7504, 2004.
164              
165             In my debian system with gcc 4.1 I had some trouble compiling cartogram.c. I had to:
166              
167             - add "#include " in the beginning cartogram.c
168             - manually link GNU math library when compiling: gcc -o cartogram -lm /usr/lib/libm.a cartogram.c
169              
170             =head1 SEE ALSO
171              
172             Geo::ShapeFile
173             http://www.santafe.edu/%7Emgastner/
174             http://www.sasi.group.shef.ac.uk/worldmapper/
175              
176             =head1 AUTHOR
177              
178             Luis Fagundes, Elhfagundes@gmail.comE
179              
180             =head1 COPYRIGHT AND LICENSE
181              
182             Copyright (C) 2006 by Luis Fagundes
183              
184             This library is free software; you can redistribute it and/or modify
185             it under the same terms as Perl itself, either Perl version 5.8.8 or,
186             at your option, any later version of Perl 5 you may have available.
187              
188              
189             =cut
190              
191             1;
192             __END__