Follow us on Twitter

Using Python with MapPoint

Share:

Python is an easy to use but powerful scripting language. Python is ideal for processing data and text. This sounds a bit like Perl, but Python is much easier to read and maintain. A wide range of available extensions make Python an ideal tool for MapPoint scripting. The first half of this page shows you the basics of controlling MapPoint with Python. The second half uses some basic Python text processing to read a file of summary US Census data and plot the filtered results in MapPoint.

Basic MapPoint Programming with Python

These examples use Python 2.4. This can be downloaded from http://www.python.org. This page assumes Python is installed into the suggested directory of c:\Python24. If you use a different directory, you will need to modify the following instructions accordingly.

To access COM, I used the Python Windows Extensions (“PythonWin”). These extensions also include a simple IDE (Interactive Development Environment), and some Windows GUI extensions. The PythonWin installer can be downloaded from http://www.python.org/windows/pythonwin. Ensure that you download the version that matches your version of Python. Install PythonWin after Python.

In order to access MapPoint’s objects and methods, you need to convert MapPoint’s COM Type Information into a form that Python can read. This is performed using the PythonWin make-py Python script. From the command line, this is performed as follows:

This example is for MapPoint 2004 North America. You will need to change the name of the directory and MapPoint’s tlb file if you are working with a different version.

The Type Information will now be contained in mpna82.py in the main Python directory.

Start Python. Type the following code in at the command prompt, or enter it into a text file and run it as a program:

A Practical Example: Creating a Map from US Census Data

Python is a scripting language that is ideally suited to text processing. Hence it can be used as a replacement for MapPoint’s Data Import Wizard in situations that require some processing intelligence. As an example, we will use it to plot the 250 largest cities in California.

Our source data is the US Census Bureau’s 2000 Gazetteer of Places. This file (places2k.txt) and format specification can be found at: http://www.census.gov/geo/maps-data/data/gazetteer.html.

The data file is a text file, with one line per place. A place is typically a town or city, although it may also be a CDP (Census Designated Place) – i.e. an unincorporated town. Each line follows a fixed column format, and includes information such as location (longitude, latitude), area, and population.

So let’s get started with some Python! First we import the required libraries and MapPoint COM information:

Python supports object oriented programming. This lets us represent a city’s information in the form of a simple object with only a constructor and some data members. This constructor takes a line of text (read from the data file) and creates a city object.

Note that Python’s tabulation is important. If a statement leads into a block, it ends with a ‘:’ and the members of the block are tabbed. So in the above code, the class CityInfo has one method, the __init__ method. This is the constructor. self refers to the object being created, and sline is a string parameter holding the text line that is to be used. Most of the lines should be self-explanatory. The strip, atoi, and atof functions are a member of the string library. These are used to extract the string and numeric data from sline, before saving it into the relevant CityInfo members.

The city name needs a bit more work. Unlike the fixed 2 character State code, city names can have a variable length and are hence padded out with space characters. The call to strip removes these spaces. The US Census Bureau also appends a city type label to the end of each city name. Examples include “city”, “town”, and “village”. These are always lower case and are removed by the removeSuffix() function, which is defined at the top of the above code snippet. This function simply looks for a particular suffix and removes it if it is present.

We will store the cities in arrays, but we also need to sort them. The array’s sort method can take custom comparison functions. We could write some quite complex comparison functions that sort on multiple parameters or calculate parameters to compare, but for now we only need to sort by population:

Now we can start with the main code. First, we must read all the city data. These are stored as CityInfo objects in a dictionary called citiesByState.

This code simply loops over each line, reading it in and creating a CityInfo object with it (referenced by the variable thisCity). These are stored in the citiesByState dictionary. Python Dictionaries work a bit like STL maps or Visual Basic collections. They store collections of objects indexed by a key. In this case, we use the State as key, and for each key we store a list of CityInfo objects. This allows us to quickly find the list of cities for a particular State. Python lists work in a similar way as dynamic arrays.

After reading all these cities, we can perform a variety of actions – for example extract cities with specific population densities. However, here we simply want the 250 largest cities in California. So first, we get a reference to the list of California cities, and then sort them by population:

Now that we have the cities sorted in order of population (largest first), we can extract the first 250 and plot them in MapPoint. Calling MapPoint in Python was covered in Part 1 of this article. Here is the city plotting code:

The Python for loop is more flexible than the Visual Basic for loop, and is capable of iterating over a list of objects. Here we just want it to iterate over the range 1-250 – hence the call to range(250). Each pin is inserted at the city’s location with the city’s name.

This is what the resulting map looks like:

Example MapPoint screenshot of California cities produced by Python

2 comments to Using Python with MapPoint

  • Jeremy Batchelor

    I have been developing a project using Python and MapPoint 2010 using the mechanisms you have very helpfully demonstrated here. The problem I have is getting MapPoint to die afterwards!

    myApp = Dispatch(MAPPOINT)
    myApp.NewMap
    myApp.Visible = 1
    myMap = myApp.ActiveMap

    [My code]

    # Tidy Mappoint up, leaving MapPoint open for the user to see
    myApp.UserControl = 1
    myMap = 0
    myApp = 0

    print “Finished!”

    I used the above approach and have experimented with alternatives to close down MapPoint, the latest of which is:

    # Tidy Mappoint up, leaving MapPoint open for the user to see
    # myApp.UserControl = 1
    myApp.ActiveMap.Saved = True
    myApp.Application.Quit
    # myApp.Quit
    myMap = None # changed from 0
    myApp = None # changed from 0
    print (“End of program”)

    Whichever approach I take, after the program finishing successfully and manually closing the remaining MapPoint window, I seem to leave MapPoint.exe running in the task manager.

    I would be very grateful for any advice.

    Many thanks, Jeremy

    • You shouldn’t need to use myApp.Application – just myApp should be sufficient. Also check that ALL references are cleared.

      Ie. first clear ALL MapPoint object references except myMap and myApp (0 or null is irrelevant). Then:

      myApp.UserControl = False
      myMap.Saved = True
      myMap = 0
      myApp.Quit
      myApp = 0

      With UserControl set to false, MapPoint will remain in memory until all references have been cleared (ie. as per a COM server). With it set to true, it will remain even after the host application has closed.

      You may need to force the garbage collector as well to make sure the cleared Python references work their way through to COM.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">