Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 10

Excel to KML - a VBA program

Article Index

Excel to KML - a VBA program

Multiple Placemarks

Polygon function

Generating markers
Page 1 of 4
A very standard requirement is to convert geographical data stored in a spreadsheet into a map.
The simplest way to achieve this is to convert the data into a KML file and then load this into Google
Earth or a similar mapping/GIS application.
 
Converting raw co-ordinates into KML isn't a difficult task but it is time-consuming and  its repetitive
nature makes it ideal for implementation as a macro. In this article we create a VBA macro that will
work with almost any version of Excel. (You can download the spreadsheet and macro from the
CodeBin - see the end of the article for details.)
If you want to know more about KML before moving on see: KML in Google Maps and Earth and if
you want to know more about using Google Earth try: Getting started with Google Earth.  If you
want to know more about VBA macros in general then see: Automating Excel.

The data
The spreadsheet is assumed to contain two columns of latitude and longitude data. In addition the
example data, a series of earthquakes (well microtremors to be less alarmist) that occurred in July
2010 in the Alboran Sea, South-East  Spain. There is a third column for  earthquake magnitude.
(The spreadsheet is available for download.)
The macro takes each of the co-ordinates. creates a KML placemark at the location and a custom
symbol - a triangle in this case. The size of the symbol is set by the magnitude of the earthquake
but you can easily customise the macro to provide fixed size symbols or link the size to some other
data.
The raw data in this case came from the database maintained by the IGN (Instituto Geográfico
Nacional) and column A is the catalog number of the events.
 
The data
To get started we need to create a new Excel macro.  exactly how you do this varies a lot between
different versions of Excel. Macros are also usually turned off for security reasons.
In most versions of Excel the command to get the Visual Basic Editor started is Tools, Macros,
Visual Basic Editor.
To get to the Visual Basic Editor in Excel 2010 is more complicated - see  Getting started with Excel
VBA.
However once you get the Visual Basic Editor started it looks the same and is used in the same
way in all versions of Excel.
The easiest way to create a user interface is to use a UserForm. A UserForm can contains buttons,
textboxes and you can use one to create a fairly sophisticated user interface. To add a UserForm to
the project use the command Insert,UserForm.
Once you have the UserForm you can use the Toolbox to add a Button, three small textboxes and
one large textbox. You can also place labels and other "decoration" to make the form look more
professional and easy to use.

The UserForm
The idea of the user interface is that when the program is started the user can set the column letters
that the Latitude, Longitude and Magnitude are stored in. When this is done the Generated KML
button is clicked the program generates the KML and it is stored in the large textbox on the right.
The user can then select it and use copy and paste to transfer it to a mapping program to a text
editor to subsequently save as a KML file. It would be quite easy to add a button or a menu option
to save the KML in a file - but copy and paste is easy and versatile.

The program
The entire program is contained in the button's click event handler - nothing happens until the user
clicks the  Generate KML button. The click handler can be generated automatically by double
clicking on the button in the UserForm editor.
The first task is to retrieve the column letters stored in each of the textboxes to discover which
columns the data is stored in. We also need to convert the column letters into column numbers to
make working with the data stored in the cells easier. The simplest way to convert a character to a
numeric value is to use the Asc functon which returns the ASCII code for the letter. To make sure
that A is converted to 1 we also have to subtract the ASCII code for A.This gives:

Private Sub CommandButton1_Click()

Dim LatCol As Integer


LatCol = Asc(TextBox1.Text)-Asc("A")+1
Dim LongCol As Integer
LongCol = Asc(TextBox2.Text)-Asc("A")+1
Dim MagCol As Integer
MagCol = Asc(TextBox4.Text)-Asc("A")+1

We can now start generating the KML as it always starts in the same way. To do this we make use
of a custom subroutine outputLine which adds the text to the textbox with a carriage return at the
end - that is it outputs a line:

Private Sub outputLine(s As String)


 TextBox3 = TextBox3 & s & vbCr
End Sub

The vbCr is a standard constant that contains the character code for carriage return.
Using this subroutine we can output the first three lines of KML:

Call outputLine("<xml version='1.0'


                     encoding='UTF-8'>")
Call outputLine("<kml xmlns
    ='http://earth.google.com/kml/2.2'>")
Call outputLine("<Document>")

Page 2 of 4
 
 

Placemarks galore
We are now ready to generate the KML for a Placemark. First it is assumed that the current sheet
i.e. the one open when the VBA program was started, is the one containing the data. If this is not
the case you need to extend the program to allow the user to specify the data sheet. It is also
assumed that the data starts in row 2 with column headings in row 1.

Dim Row As Integer


Row = 2

Again, if this is not the case you need to give the user some way to modify the default.
Now we get to the part of the code that does the real work. We use a Do loop to extract the data
from each row, process it and then move on to the next row. The loop ends when the Longitude
column contains a blank The test could be on any column - its just a matter of detecting when there
is no more data to process.

Do Until (Cells(Row, LongCol) = "")


Call MakePlaceMark(
      Cells(Row, LongCol),
      Cells(Row, LatCol),
      Cells(Row, MagCol))
Row = Row + 1
Loop

The work of generating the KML for the Placemark is done by the MakePlaceMark subroutine which
we have yet to write. Notice the way that the Cells function is used to get the data sorted in the cell
at a specified row and column. That is:

Cells(row,col)

retrieves the value in the cell at the intersection of row and col where column A is col=1 column B is
col=2 and so on.
After generating all of the KML for one Placemark for each row of data all that remains is to write
the customary closing KML tags:

Call outputLine("</Document>")
Call outputLine("</kml>")
End Sub

The complete subroutine is:

Private Sub CommandButton1_Click()


Dim LatCol As Integer
LatCol = Asc(TextBox1.Text)-Asc("A")+1
Dim LongCol As Integer
LongCol = Asc(TextBox2.Text)- Asc("A")+1
Dim MagCol As Integer
MagCol = Asc(TextBox4.Text)-Asc("A")+1

Call outputLine("<xml version='1.0'


                  encoding='UTF-8'>")
Call outputLine("<kml xmlns=
  'http://earth.google.com/kml/2.2'>")
Call outputLine("<Document>")

Dim Row As Integer


Row = 2
Do Until (Cells(Row, LongCol) = "")
Call MakePlaceMark(
    Cells(Row, LongCol),
    Cells(Row, LatCol),
    Cells(Row, MagCol))
Row = Row + 1
Loop
Call outputLine("</Document>")
Call outputLine("</kml>")
End Sub

Making a Pacemark - using an icon


Now we have to write a subroutine that generates the KML for a Placemark. This is fairly easy but
there is a tricky part in generating the graphics for a custom shape.
The subroutine starts:
Private Sub MakePlaceMark(
             lon As Double,
             lat As Double,
             mag As Double)

lat and lon are parameters which specify the position of the Placemark and in this case mag is a
parameter that controls the size of the symbol drawn. Notice that you can't use "long" as the name
of the longitude parameter because long is a reserved word i.e. it means something special to VBA.
Now we simply write the standard KML for a Placemark:

 Call outputLine("<Placemark>")
 Call outputLine("<Point> <coordinates>")
 Call outputLine(lon & "," & lat)
 Call outputLine("</coordinates> </Point>")
 Call outputLine("</Placemark>")

End Sub

The position parameters are output to set the Placemark's position. If you use this version of the
MakePlaceMark subroutine then a standard Placemark icon is used. This might be what you want in
which case the program is finished.
The complete MakePlaceMark sutroutine is:

Private Sub MakePlaceMark(


            lon As Double,
            lat As Double,
            mag As Double)

 Call outputLine("<Placemark>")
Call outputLine("<Point> <coordinates>")
Call outputLine(lon & "," & lat)
Call outputLine("</coordinates> </Point>")
Call outputLine("</Placemark>")

End Sub

Here, however, we want to scale the symbol used for the placemark and to do this we will draw the
outline of a polygon. To do this we first need another subroutine to generate the points that define it.

Page 3 of 4
 

The Polygon function


To draw a regular polygon as a symbol we first need to write a small function that will
return the co-ordinates of the points of the corners of the polygon give its center and
"radius".
This is easier to write than you might think, once you know  the equation for a circle in
polar co-ordinates:
cx= r*Cos t + + x
cy= r*Sin t + y

which gives a point on the circle of radius r centered on x,y at angle t.

To generate the points of an n-sided polygon we simply need to evaluate the formulas for t
equal to mulitples of 2Pi/n. For example for a triangle the angle is 2Pi/3:

The only complication is that a XML polygon has two extra requirements. The first is that
you have to repeat the first point in its specification as the last point - i.e. to close the figure.
The second is that the points have to be listed in a clockwise order.
With these two practicalities in mind we can write the polygon function. First we need to
setup some basic variables and constants:
Private Function Polygon(
      x As Double,
      y As Double,
      r As Double,
      n As Integer) As String
Dim Angle As Double
Dim Coords As String
Coords = ""
Angle = 2 * 3.141592654 / n

The number of points to be generated is given by n and the results are to be returned in the
Coords string as a set in the format x,y,z with one point to a line.
The first and last points are best generated separately from the rest. The first point is:
px1 = r * Sin(Angle * i) + x
py1 = r * Cos(Angle * i) + y
Coords = Coords & px1 & "," & py1 & ",0 "

The final line converts the numeric values px1 and py1 into a comma separated string.
Next we use a for loop to generate the rest of the points in the polygon:
For i = 1 To n - 1
 px = r * Sin(Angle * i) + x
 py = r * Cos(Angle * i) + y
 Coords = Coords & px & "," & py & ",0 "
Next i

Finally we repeat the first point as the last point and return the result:
 Coords = Coords & px1 & "," & py1 & ",0"
 Polygon = Coords
End Function

The complete function is:


Private Function Polygon(
      x As Double,
      y As Double,
      r As Double,
      n As Integer) As String
 Dim Angle As Double
 Dim Coords As String
 Coords = ""
 Angle = 2 * 3.141592654 / n

 px1 = r * Sin(Angle * i) + x
 py1 = r * Cos(Angle * i) + y
 Coords = Coords & px1 & "," & py1 & ",0 "

 For i = 1 To n - 1
  px = r * Sin(Angle * i) + x
  py = r * Cos(Angle * i) + y
  Coords = Coords & px & "," & py & ",0 "
 Next i

 Coords = Coords & px1 & "," & py1 & ",0"
 Polygon = Coords
End Function
Page 4 of 4
 

Generating the marker


Now we can use the ability to calculate the position of the points in a polygon we can write a version
of the MakePlacemark subroutine that marks locations with triangles (or any polygon) with a
"radius" determined by the magnitude.
First we have to ouput the tags that define a drawing style for the polygon - the color set is red but
this could easily be changed or be set by another parameter in the subroutine call:

Call outputLine("<Style><PolyStyle>
       <color>ff0000ff</color>
       <fill>1</fill>
       <outline>1</outline>
       </PolyStyle></Style>")

Next we output the tags to define the polygon graphics object:

Call outputLine("<MultiGeometry>
    <Polygon> <outerBoundaryIs>
      <LinearRing><coordinates>")

Now we make use of the polygon function to output the coordinates:

Call outputLine(Polygon(lon, lat,


                           mag/500, 3))

Finally we write the closing tags:

 Call outputLine("</coordinates>
       </LinearRing></outerBoundaryIs>
            </Polygon></MultiGeometry>")

 Call outputLine("&lt;/Placemark>")
End Sub

This is all that is required and if the program is run on the data a KML file with one symbol per line
of data is generated in the large textbox.
 

Using the KML with Google 


To actually make use of the KML generated you have to load it into a suitable mapping program -
either by creating a KML file or by copy and paste.
To create a file all you have to do is select the data in the textbox (Ctrl+A), copying (Ctrl+C) and
pasting (Ctrl+V) into Notepad allows you to save the KML in a file called earthquake.kml.
This can be viewed in Google Maps by entering
http://www.i-programmer.info/maps/earthquake.kml
into the search box.

Microtremors in the Alborán Norte 4-10 July 2010


 
An alternative is to simply copy the KML from the text box and paste it into Google Earth. You can
also use the File,Open command and enter the URL:
http://www.i-programmer.info/maps/earthquake.kml
 

Microtremors in the Alborán Norte 4-10 July 2010


 
Of the two, Google Earth does a better job of displaying custom KML as Google Maps only supports
a subset of the KML specification.
If  you are interested in this seismic sequence the IGN has produced a report on it.
The program can easily be modified to generate more complex symbols or to use additional data to
control the color of symbols for example.
To access the spreadsheet - data and macro - for this project, once you have registered,  click
on CodeBin.
 
If you would like to be informed about new articles on I Programmer you can either follow us
on Twitter, on Facebook , on Digg or you can subscribe to our weekly newsletter.

You might also like