Archive for the ‘Scripting’ Category

Embedding a custom Google mashup

Problem: You need to display GIS data on a webpage on top of a familiar basemap with basic zoom and pan tools.

There are many ways to do this. The one I will explain today doesn’t require programming skills, specially configured servers or proprietary software. Note: I borrowed heavily from Havard University’s Google Maps tutorial for this entry. They have an excellent free web-based GIS Technical Training Workshop Series.

The basic map they provide is all you really need to get started. The HTML file is structured and commented in such a user-friendly way that you will be able to start editing it to make common customizations to your map almost immediately. No need to wade through the Google Maps API Documentation until you’re ready to try something more complicated.

Go to http://maps.cga.harvard.edu/samples/basic.html and save the html source document (basic.html) to your harddrive. Then open it in a text editor.

The first thing you will probably want to change is the area of the world that the map is showing. To do that, change this bit of code, which is right now centered and zoomed to show the United States.
//Sets the initial map location and zoom level (latitude, longitude) in decimal degree format (zoom level) 1 - 21
gmap.setCenter(new GLatLng(39.10960, -96.5), 4);

For my example, I’m going to make a map of the recent Haiti earthquake. There’s been a lot of that going on recently as geo-Pros have been banding together to speed information to the relief workers.

I’ve changed my center coordinates to the location of the main quake, and upped my zoom so Hispaniola island fills the screen:
gmap.setCenter(new GLatLng(18.44, -72.54), 7);

Now, I’m going to change the starting style to make it a little less busy, since I’m going to be adding things. Uncomment the second line in the code here.
//Sets the initial map to load. Change between PHYSICAL, SATELLITE, HYBRID, NORMAL. Default is NORMAL
//gmap.setMapType(G_PHYSICAL_MAP);

When commented out, it will default to NORMAL. If you want to change that, you will need to delete the // in front and change it to one of the options above. Like so:
gmap.setMapType(G_HYBRID_MAP);

Note: PHYSICAL is an attractive terrain map that is not available in standard google maps. It’s tempting to use it, but it’s still too bright for the things I’m going to add next to show up well.

My map is centered on the location of the quake, but I also want to add a pointer to show exactly where it happened. To do that, insert the following code after the line where you changed the background map style.

//Adds a marker with window information
function createMarker(point,html) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
var point = new GLatLng(18.44,-72.54);
var marker = createMarker(point,'Magnitude 7.0 Earthquake Jan 12, 2010');
gmap.addOverlay(marker);
//End of add marker code

The editable areas in red are where you can change the coordinates of the marker and the description in the pop-up box.

I will also plot the locations of a couple aftershocks that occurred over a week after the initial event. I got these locations from the USGS Earthquake Search page at http://neic.usgs.gov/neis/epic/epic_circ.html
var point = new GLatLng(18.38,-72.85);
var marker = createMarker(point,'Magnitude 4.9 Aftershock Jan 21, 2010.');
gmap.addOverlay(marker);
var point = new GLatLng(18.48,-72.45);
var marker = createMarker(point,'Magnitude 4.4 Aftershock Jan 22, 2010.');
gmap.addOverlay(marker);

You can continue adding as many points as you like in this fashion.

You will probably want to change your markers so they don’t all look the same. In my case, I would like to distinguish the earthquake from the aftershocks. You can use any of the icons shown on this page, instead of the default marker. To do that, add this code block right before the //Adds a marker with window information block:

//javascript that sets up variables that enable the map to draw a custom icon.
var baseIcon = new GIcon();
baseIcon.iconSize=new GSize(32,32);
baseIcon.shadowSize=new GSize(56,32);
baseIcon.iconAnchor=new GPoint(16,32);
baseIcon.infoWindowAnchor=new GPoint(16,0);
var custom_icon = new GIcon(baseIcon, "http://maps.google.com/mapfiles/kml/pal3/icon28.png", null, "http://maps.google.com/mapfiles/kml/pal3/icon28s.png");
//end of custom icon code

Change the red pal group number and icon number to match the icon you want to use. Then, add the blue text to the end of these lines:

//Adds a marker with window information
function createMarker(point,html,icon) {
var marker = new GMarker(point,icon);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
var point = new GLatLng(18.44,-72.54);
var marker = createMarker(point,'Magnitude 7.0 Earthquake Jan 12, 2010.', custom_icon);
gmap.addOverlay(marker);

Note: if you wanted to use two types of icons, you could define (for example) a custom_icon2 above and assign it below, in the same manner.

It is simple to add KML files, which were developed for use with Google Earth, to these maps. Although shapefile is still the most common format, KML is becoming more and more available. My favorite new data search tool, the Geocommons Finder! offers its entire catalog in KML format (along with SHP and CSV).

To add a KML layer that shows the locations of hospitals in Haiti, you’d insert the following code right before the //Close bracket for the function initialize:
//Adds a kml overlay
var geoXml = new GGeoXml("http://finder.geocommons.com/overlays/20906.kml");
gmap.addOverlay(geoXml);
//End of kml overlay code

You can add as many of these as you like, and change the URL to point to whatever file you’d like. Note: If you, like me, have most of your data in other formats, you can use Havard’s Export to KML: Version 2.4 ArcGIS extension (see list on right side of page) before adding it to a mashup.

Here’s my Haiti map with all the changes I described. View the source to see them in context.

Tags: , , , ,

Adding a button that will run custom code

Problem: You have written or found a script that you would like to be able to run by pressing a button on your ArcMap toolbar

There is a world of ways to extend to the basic functionality of ArcGIS, beyond just installing plugins. People have been writing custom code for years in various languages, and making it available in places like ArcScripts and the ESRI Developer Network.

Today I will show you how to take a script from a place like that and attach it to a button in your ArcMap toolbar so it will be available whenever you run the application. I have begun learning to program ArcObjects with Visual Basic for Applications, so I chose a VBA sample as my example code. The code I found will spell check label text using the Microsoft Word spell checker. It is available in the ESRI Developer Network code exchange here.

Note: The ESRI Developer Network is moving to the ArcGIS Resource Center for versions 9.3 and above. Newer sample VBA codes are available through the resource center here: http://resources.esri.com/help/9.3/arcgisdesktop/com/vba_start.htm

Before you worry about the code, you need to create your button. You can add a new button to any toolbar by right clicking on that bar and selecting Customize. If you go to the Commands tab and scroll all the way to the bottom, you will see a [ UI Controls ] option. If you highlight it you will be able to press a button to create a new UI (User Interface) Control.

If you save the control in Normal.mxt, it will will show up in every ArcMap session from now on. You can also save it only in the current .mxd, if you prefer. Select a UIButtonConrol, and click Create. Normal.UIButtonControl1 will now show up in your Commands list box. “Normal” indicates where you are saving the command and “UIButtonControl1″ is the name of the command. If you click on it you will be able to rename it to something more descriptive. I chose Normal.SpellCheck. Now, you can highlight it and drag it to any toolbar.

If you right click on the new button while the Customize dialog is still open, you will be able to change its appearance. You can chose from a selection of images, browse to a custom image, add text with the image, or chose text only. I did text only. Your command name will be used as the button text. At this point, if you pick View Source off the same menu, the Visual Basic Editor will open. A window will appear where you can paste the code for the spell check tool. You can get the code from here:
http://edndoc.esri.com/arcobjects/9.2/CPP_VB6_VBA_VCPP_Doc/COM_Samples_Docs/ArcMap/9be43e79-834e-42a2-96c8-59b0dba3180b.htm

Copy everything between…

Public Sub SpellCheck()

and

End Sub

…but don’t copy the opening or closing line itself. Visual basic has already added those lines for you, formatted correctly to work with the button you created. For instance, mine starts as:

Private Sub SpellCheck_Click()

Now, you will notice in Step 3 of the “How to Use” instructions that the developer tells you to add a reference to the Microsoft Word Object Library. You can add references by going to the Tools menu and selecting “References..”. The following list will come up. Scroll down and check off the appropriate library.

Be sure you save Normal.mxt (File menu or disk button) before exiting the Visual Basic Editor. Now, when you’re back in ArcMap, create some text labels. Then select one of them and press your new button. If you have any misspelled words in the selected label, a spell checker will pop up that should look quite familiar! Any corrections you make will be carried over to the label.

If you would like to learn more about ArcObjects and VBA, Getting to Know ArcObjects by Robert Burke seems great so far. It’s what I’m reading now.

Tags: , , ,

Removing Empty Feature Classes with Python

The Problem: You have a geodatabase with a lot of empty feature classes

This often happens if the geodatabase has been created from a template of standard themes, but this particular version doesn’t contain information to stick into all the available slots. It can be difficult to get a handle on what’s actually there with all the empty feature classes clogging up space. It can take up extra processing time or cause errors depending on what you’re doing with the data later. And, it’s just bad organization. The best practice is to get rid of them. You can do so by moving down the feature class list in ArcCatalog, checking for empties and deleting them one by one. But with large databases (the kind that need trimming down the most) this can take a lot of time.

The slow manual method:
Right click to delete feature class

The fast automated method: use this python code that an associate shared with me!

Copy and paste the following into any text editor and save it as a python .py file.

##############################################################
##  Delete Empty Feature Classes from Multiple Geodatabases
##
##  This script loops through all geodatabases within a directory
##  and removes empty featureclasses from each geodatabase.
##
##  User must hardcode directory.  Run this script in IDLE.
##
##  Python Version 2.4
##############################################################

# Create the Geoprocessor object
import arcgisscripting, os, sys, string
gp = arcgisscripting.create()

# Load required toolboxes...
gp.AddToolbox("C:\\Program Files\\ArcGIS\\ArcToolbox\\Toolboxes\\Conversion Tools.tbx")

# Set workspace
gp.workspace = "C:\\Documents and Settings\\user\\Desktop\\gis\\"

# list personal geodatabases in the current workspace
listmdb = gp.listworkspaces("*", "access")
mdb = listmdb.next()

# loop through the personal geodatabases
while mdb:
    print mdb
    gp.workspace = mdb
    # list feature datasets in personal geodatabase
    listfdset=gp.listdatasets()
    fdset=listfdset.next()
    if not fdset == None:
        gp.workspace = mdb + "\\" + fdset
    # list feature classes in the personal geodatabase
    fcs = gp.listfeatureclasses()
    fcs.reset()
    fc = fcs.next()

    # loop through the featureclasses
    while fc:
       # print fc

        # if the feature class table has no records, delete the featureclass
        if gp.GetCount_management(fc) == 0:
            gp.Delete_management(fc)
            print fc + "deleted from" + mdb
        fc = fcs.next()

    mdb = listmdb.next()


The only thing you will need to change is the directory under # Set workspace. Put the path to your geodatabase(s) in between the gp.workspace = “” quotes, remembering to use two slashes \\ in between folder names.

This works with personal geodatabases. If you are using file geodatabases, go to the next line under # list personal geodatabases… and replace “access” with “FileGBD” between the gp.listworkspaces(“*”, “”) quotes.

Now, start Python IDLE, which ships with the ArcGIS suite. Open up your .py file. Then, select Run –> Run Module (or hit F5). This is what you will see:
Python module in IDLE
Python results in IDLE
It may take some time to run, but that is time you can spend doing other things. When it’s done, those empty feature classes are history.

You can edit, save and rerun the .py file as many times as you need if your geodatabases are spread between different directories. (Or, for even more automation, copy them all into the same directory before you start, and let the script loop through them).

Python is an extremely handy tool. If you are interested in learning more about it, see the resources below.

Tags: , , ,

Bad Behavior has blocked 21 access attempts in the last 7 days.