Showing posts with label perl. Show all posts
Showing posts with label perl. Show all posts

Wednesday, August 27, 2008

Perl: Make KML from NOAA Forecast

I wanted a simple way to make GoogleMaps KML to show forecasted storm tracks. The forcasted storm tracks can be downloaded from the National Hurricane Center and generally look like this. This is today's forecast for TS Gustav:


INITIAL 27/1500Z 18.8N 74.0W 50 KT
12HR VT 28/0000Z 19.0N 74.8W 55 KT
24HR VT 28/1200Z 19.2N 76.0W 60 KT
36HR VT 29/0000Z 19.3N 77.5W 70 KT
48HR VT 29/1200Z 19.9N 79.4W 80 KT
72HR VT 30/1200Z 21.5N 83.0W 100 KT
96HR VT 31/1200Z 24.5N 86.0W 100 KT
120HR VT 01/1200Z 28.5N 88.5W 100 KT

So I wrote a Perl program to translate that into a KML file. The program looks like this:

use strict;
#Get the storm name from the user
print "Storm Name? ";
my $storm = <STDIN>;
chomp($storm);

#Print out the KML header
print << "STARTLINE";
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>$storm</name>
<open>1</open>
<description>NOAA $storm track</description>
<Folder>
<name>Placemarks</name>
<description>$storm</description>
<Placemark>
<name>$storm</name>
<LineString>
<tessellate>1</tessellate>
<coordinates>
STARTLINE

# Build kml stanzas for the line and forecast markers
my $line = "";
my $points = "";
while(<DATA>) {
chomp;
if (m/^ *(INITIAL|\d+HR VT) +(\d+\/\d{4}Z) (\d+\.\d+)N +(\d+.\d+)W +(.*)$/) {
$line .= "-$4, $3\n";
$points .= << "HERE"
<Placemark>
<name>$1, $2, $5</name>
<Point>
<coordinates>-$4, $3</coordinates>
</Point>
</Placemark>
HERE
}
}
# Print everything out, including the end of the kml
print $line;
print << "FINISHLINE";
</coordinates>
</LineString>
</Placemark>
FINISHLINE
print $points;
print << "FINISHPOINTS";
</Folder>
</Document>
</kml>
FINISHPOINTS
__DATA__
INITIAL 27/1500Z 18.8N 74.0W 50 KT
12HR VT 28/0000Z 19.0N 74.8W 55 KT
24HR VT 28/1200Z 19.2N 76.0W 60 KT
36HR VT 29/0000Z 19.3N 77.5W 70 KT
48HR VT 29/1200Z 19.9N 79.4W 80 KT
72HR VT 30/1200Z 21.5N 83.0W 100 KT
96HR VT 31/1200Z 24.5N 86.0W 100 KT
120HR VT 01/1200Z 28.5N 88.5W 100 KT


As you can see, I copy and paste the NOAA storm forecast into the program. The resulting GoogleMap looks like this:

View Hurricane Gustav Forecast in a larger map
Oh my, that looks uncomfortable for New Orleans. Keep your fingers crossed.

Friday, January 26, 2007

Perl program to calculate major triad chord progressions

I've been playing guitar for 31 years (good lord I'm old). But I only recently got interested in learning the theory behind chord progressions. I wrote this simple piece of code to calculate major triad chord progressions in all of the keys. I suppose it could be extended easily to create minor chord progressions as well.




use strict;

sub chord_progression
{
# The parameter is the index of the root note in the @notes array
my $i = shift;
my @notes = ('C', 'C#/Db', 'D', 'D#/Eb', 'E', 'F', 'F#/Gb',
'G', 'G#/Ab', 'A', 'A#/Bb', 'B');
my @intervals = (0, 2, 4, 5, 7, 9, 11, 12);

# Create a scale based on the intervals in a major scale
my @scale = map {$notes[($i + $intervals[$_]) % 12]} (0..7);

# Create triads. Increment each note within the scale.
# All notes in the chord progression fall within the
# major scale.
my ($root, $third, $fifth) = (0, 2, 4);
my @name = ('Maj', 'min', 'min', 'Maj', 'Maj', 'min', 'Dim', 'Maj');
for (0..7) {
printf "%6s %3s: %6s, %6s, %6sn",
$scale[$root], $name[$_], $scale[$root],
$scale[$third], $scale[$fifth];
$root++;
$third++;
$fifth++;
$root %= 7;
$third %= 7;
$fifth %= 7;
}
print "n";
}

# Call the subroutine for each note in the scale
for (0..11)
{
chord_progression($_);
}


This produces output like this for the 12 root notes:



C Maj: C, E, G
D min: D, F, A
E min: E, G, B
F Maj: F, A, C
G Maj: G, B, D
A min: A, C, E
B Dim: B, D, F
C Maj: C, E, G
----------------------------------
C#/Db Maj: C#/Db, F, G#/Ab
D#/Eb min: D#/Eb, F#/Gb, A#, Bb
F min: F, G#/Ab, C
F#/Gb Maj: F#/Gb, A#, Bb, C#/Db
G#/Ab Maj: G#/Ab, C, D#/Eb
A#, Bb min: A#, Bb, C#/Db, F
C Dim: C, D#/Eb, F#/Gb
C#/Db Maj: C#/Db, F, G#/Ab
...

Tuesday, September 19, 2006

Perl script to split MP3 files

This is a simple script I used recently to split a large (50 minute) MP3 file into a series of smaller files. I used the MP3::Splitter module. MP3::Splitter is very versatile, so what I am doing does not use all of its functionality. But this does a good quick and dirty job of chopping up a file into bits. This comes in handy so you don't have a huge file to fast forward through on your iPod or other MP3 player.

The first two parameters of mp3split are the name of the file and a hash with options-- the only one I use is to set "verbose" to true. After that are a series of array references that describe each bit I want written out to a file.

The first parameter is the start time. I start the very first piece at 0 minutes. After that, each bit starts relative to the end of the last bit-- this is marked by the > symbol.

The next parameter shows how long the bit should be in seconds-- I chose to make each one two minutes long.

Since my MP3 file was about 50 minutes long, I just made 25 two minute bits. The last bit has a special marker as the finish: =INF. This means to use all of the rest of the file.




use MP3::Splitter;
mp3split('01-italian.mp3', {verbose => 1},
["0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "120"],
[">0", "=INF"]
);

Wednesday, August 30, 2006

Perl one-liner: sort a string of numbers

This is a stupid pet trick with Perl.

I was recently writing an email to a cow-orker and had a long list of numbers to put in the email. I had them like this:




56165, 55163, 56137, 56104, 56115, 55108, 56971, 55768, 56682, 56585, 55940


My cow-orker likes things to line up and be in order, so I needed to sort them. I reckoned I could use split, sort, and join in Perl to make this job easy. It worked. Here is the one-liner I came up with:




perl -e "@_=split(/, /,'56165, 55163, 56137, 56104, 56115, 55108, 569
71, 55768, 56682, 56585, 55940');print join(', ',(sort @_))"

55108, 55163, 55768, 55940, 56104, 56115, 56137, 56165, 56585, 56682, 56971


Shiny.

Monday, August 7, 2006

Using the Perl Xbase module to read xBase databases

I recently had occasion to read some xBase database files (e.g. dBase or FoxPro files). What I was doing needed some of the capabilities of Perl. I found a module that reads xBase databases directly: Xbase.

Here is a simple set of code to read all of the records in an xBase database:




use strict;
use Xbase;

# Create a new Xbase object
my $database = new Xbase;

# Open the database
my $db_name = 'C:exampledatabase.dbf';
$database->open_dbf($db_name);

# Get the last record number
my $end=$database->lastrec;

# Go to the first record
$database->go_top;

# Loop through the records
for my $i (1..$end)
{
# Print the record number
print $database->recno . ". ";

# Get the fields in this record
my @fields = $database->get_record;

# Loop through the fields
for my $f (0..$#fields)
{
# Print the values of each field
print $fields[$f] . "\t";
}
print "\n";

# Go to the next record
$database->go_next;
}


# Print information about the database,
# including the names of the fields
print $database->dbf_type . "\n";
print "Last update: " . $database->last_update . "\n";
print $database->dbf_stat;

# Close the database
$database->close_dbf;


This code is adapted from the perldoc documentation of the Xbase module.

Friday, May 5, 2006

MS Access: VBA Regular Expressions (RegEx)

As a Perl programmer (hey, I founded Barcelona Perl Mongers), I always am looking for Perlish features in other languages. I know VBA (Visual Basic for Applications) is not a beautiful language, but I run into so very often that I actually use it more than Perl now. And I've found that it has plenty of Perlish features. Two of the most useful for me have been Associative Arrays (i.e. hashes) in the form of the Dictionary object, and Regular Expressions. Recently a friend asked me how to extract ZIP codes from a field in a Microsoft Access table in a SELECT statement. For example, she wanted to say:


select some_function(ZIP_expression)
  from some_table;
on a table with values like "Philadelphia, PA 19107-1234" or "Lumberton, TX 77657" and have it return just the ZIP. I couldn't make an unwieldy version of this using just INSTR, MID, etc. Maybe there is a way. However, there is an elegant solution using regular expressions. You have to include a new Access module, and put this code in it. Prior to putting the code in, you have to include a reference to "Microsoft VBScript Regular Expressions 5.5" (Tools->References):

Function zipfinder(t As String)
    Dim re As New RegExp
    ' Look for five digits.  Optionally, look for a dash and four digits
    re.Pattern = "\b(\d{5}(-\d{4})?)\b"
    ' This version finds the first match.
    ' If you want the last match, set Global to false.
    re.Global = False
    Dim m
    For Each m In re.Execute(t)
        zipfinder = m.Value
    Next
End Function
Then you can use this as a function in a SELECT statement:

select zipfinder( ZIP_expression)
  from some_table;