Before I settled on the method described in this post, I tried a few other ways of visualizing the intensity of WMS requests. One other method inserted the bounding boxes into a Postgres table, and output a shapefile. Those shapefiles were quite large and difficult to handle, though they did make some interesting pictures.
Now, a few details about the process I found worked best.
PDL might give this error: “Error reading magic number from Netpbm image stream.” But you can ignore it because the image is still produced.
PDL normally outputs 8-bit TIFF files. A TIFF with only 8-bits is not enough to contain all the hits that every pixel receives because the maximum value of any pixel in an 8-bit image is 255. I had to output 16-bit TIFF, for which the maximum value is 65,535.
Load the required modules, and initialize some variables. This script works against a service in geographic projection, but it could be modified to work on any projection. Left, right, top and bottom define the crop region of the map. This reduces processing time and memory requirements if we ignore a lot of the Pacific and anything North of 50 degrees latitude. Columns and rows or the TIFF are computed from the bounds and from the degree size. Degree size determines the final resolution of the TIFF. A degree of size 8 will make pixels the same size as 7.5 minute quadrangles. The larger the number, the longer this script will run and the larger the output files.
use PDL;
use PDL::NiceSlice;
use PDL::IO::Pic;
use PDL::IO::FlexRaw;
my $degree_size = 128;
my $myfile = "log";
my $left = -125;
my $right = -65;
my $top= 50;
my $bottom = 23;
my $width = $right-$left;
my $height = $top - $bottom;
my $cols = $width * $degree_size;
my $rows = $height * $degree_size;
my $blank_slate = zeroes($cols,$rows)->ushort;
open(LOG, "log.txt") || die;
#for each line of the log
if (m/REQUEST=GETMAP/i) {
my ($bboxString) = ($_ =~ m/BBOX=(.+?)[\&|\n|\s]/i);
$bboxString =~ s/%2C/,/g;
$bboxString =~ s/%2D/-/g;
$bboxString =~ s/%2E/./g;
my @splitbbox = split(',', $bboxString);
my $w = $splitbbox[0];
my $s = $splitbbox[1];
my $e = $splitbbox[2];
my $n = $splitbbox[3];
if($w<=$right && $w>=$left && $e<=$right && $e>=$left && $s>=$bottom && $s<=$top && $n>=$bottom && $n<$top && $e !=$w && $n !=$s ){ if($w <= $left ){ $w=0; } else { $w -= $left} if($e >= $right ){ $e=$width; } else { $e -= $left} if($n >= $top ){ $n=0; } else { $n -= $top} if($s <= $bottom ){ $s=$height; } else { $s -= $top} $w *= $degree_size; $e *= $degree_size; $n *= $degree_size; $s *= $degree_size; $w += 1; $n -= 1; if($s >= $rows){$s -=1;} if($e >= $cols){$e -=1;}
$blank_slate($w:$e, $n:$s) += 1;
my $fh = new IO::File "> temp.pnm";
print $fh "P5\n";
print $fh join(' ', $blank_slate->dims) . "\n";
print $fh "65535\n"; #the magic number
writeflex($fh, $blank_slate(:,-1:0));
$fh->close;
system("pnmtotiff temp.pnm >images/$degree_size/$myfile.tif");
unlink("temp.pnm");
my $resolution = 1/$degree_size;
my $left_location = $left - ($resolution/2);
my $up_location = $top - ($resolution/2);
open (WORLD, ">images/$degree_size/$myfile.tfw");
print WORLD qq^$resolution
0
0
-$resolution
$left_location
$up_location^;
close WORLD;