Wednesday, November 24, 2010

Reclassify Shapefile using Python

Reclassifying data is pretty standard in the GIS world. In the Raster realm using ESRI its pretty easy, simply create a reclass table. But occasionally (in my case often) you'll find yourself needing to reclassify vector data. Enter Python to help save your sanity. Below you'll find a simple function that accepts a value and Python dictionary. To use, first create a function to define a dictionary (your reclass table) then simply iterate through your shapfile and pass the value, and dictionary. Easy and simple but what a time saver...

  import arcgisscripting    
  gp = arcgiscripting.Create(9.3)   
    
 # DEFINE THE RECLASS TABLE   
 def reclassTable():   
   myDict:{'a': range(0, 11),   
      'b': range(11, 21),   
      'c': range(21, 31),   
      'd': range(31, 100)}   
   return myDict    
   
 # THE RECLASS FUNCTION   
 def reclass_Function(value, classDict):   
   for cls, rng in classDict.iteritems():   
    if value in rng:   
     return cls   
   return -9999   
     
 # THE READ AND WRITE FUNCTION   
 def classify_Data(inputSHP, oldFieldVals, newField):   
   gp.addField(inputSHP, newField, 'TEXT', 5)   
      
   rows = gp.UpdateCursor(inputSHP)   
   row = rows.Next()   
     
   while row:   
    row.SetValue(newField, reclass_Function(row.GetValue(oldFieldVals), reclassTable()))   
    rows.UpdateRow(row)   
    row = rows.Next()   
     
 # PASS THE VALUES   
 if__name__=='__main__':   
   inputSHP = 'C:/temp/myShapefile.shp'   
   classify_Data(inputSHP, 'KWh', 'Class')   
   
Now simply edit the dictionary to fit your needs and pass the values accordingly.

Saturday, November 20, 2010

The Hydrogen Viewer

The Hydrogen Viewer was a project I worked on several months ago. I was tasked with providing a visualization of hydrogen station installations over time. Although spatial-temporal in nature it still was not the most exciting data...so I decided to spice it up using Flex, Google Maps and a couple custom components and features. I'll cover a couple of them here.

Having a reference or background is key to any map but sometimes the reference layer can take away from the data you are really trying to highlight. Enter the gray-scale mat. Applying a grayscale mat to your Google Map really makes your data pop out and it is easy. Simply apply a color matrix filter in your "onMapReady" function.
 APPLY A GRAYSCALE TO A GOOGLE MAP
1:  private function onMapReady(event:Event):void{
2:    map.setCenter(new LatLng(38, -110), 3, MapType.NORMAL_MAP_TYPE);
3:    var mat:Array = [0.3086,0.6094,0.082,0,-100,0.3086,0.6094,0.082,0,-100,0.3086,0.6094,0.082,0,-100,0,0,0,1,0];
4:    var colorMat: ColorMatrixFilter = new ColorMatrixFilter(mat);
5:    var s1: Sprite = map.getChildAt(1) as Sprite;
6:    var s2: Sprite = s1.getChildAt(0) as Sprite;
7:    s2.filters = [colorMat];}

Creating a custom marker info window allows you maintain a consistent theme throughout your app. You can accomplish this with the following (I used one function for all of this):

CREATE CUSTOM INFO WINDOW
 
First, create your marker. I generally use custom markers:
1:  var point:Sprite = new Sprite();
2:  point.graphics.beginFill(color, .9);
3:  point.graphics.lineStyle(1, 0xFF2F4F4F, 1);
4:  point.graphics.drawCircle(0, 0, size);
5:  point.graphics.endFill();
6:  
7:  markerOptions:MarkerOptions = new MarkerOptions();
8:  markerOptions.icon = point;
9:  markerOptions.clickable = true;
10:  markerOptions.hasShadow = false;
11:  marker = new Marker(new LatLng(yPosition,xPosition), markerOptions);

Then create the content of the window:
1:  var content:Sprite = new Sprite()  
2:  var contentText:TextField = new TextField();  
3:  contentText.autoSize=TextFieldAutoSize.LEFT;  
4:  contentText.multiline = true;  
5:  contentText.htmlText = "INSERT YOUR INFO HERE!"  
6:  contentText.textColor = 0xFFFFFFFF;  
7:  content.graphics.clear();  
8:  content.graphics.beginFill(0xFF000000, 0);  
9:  content.graphics.drawRect(0, 0, 50, 45);  
10:  content.graphics.endFill();  
11:  content.addChild(contentText);  

Next, create a smart info window to place the content in:
1:  var infowindow:SmartInfoWindow = new SmartInfoWindow();  
2:  infowindow.position = infowindow.getBestAlignment(map, marker.getLatLng(), new Point(content.width, content.height));  
3:  infowindow.padding = 10;  
4:  infowindow.cornerRadius = 3;  
5:  infowindow.fillStyle = new FillStyle({color:0xFF000000, alpha:.8});  
6:  infowindow.strokeStyle = new StrokeStyle({color:0xFFC0C0C0,alpha:.8, thickness:1.5, pixelHinting:true});  
7:  infowindow.setContent(content);  
8:  infowindow.render();  

Almost there! Create info window options and assign it the custom info window created above:
1:  var options:InfoWindowOptions = new InfoWindowOptions();  
2:  options.customContent = infowindow;  
3:  options.customOffset = infowindow.anchorPoint;  
4:  options.hasShadow = false;  
5:  options.drawDefaultFrame = false;  
6:  options.hasCloseButton = true;  
7:  options.customCloseRect = infowindow.closeButtonRect;  
8:  options.pointOffset = new Point(0,-5);   

Lastly, create an event listener and add the marker to the map:
1:  marker.addEventListener(MapMouseEvent.CLICK, function (e:MapMouseEvent):void{map.openInfoWindow(e.target.getLatLng(),options);});  
2:  map.addOverlay(marker);   

There are a couple other features I think that bring this little app full circle. The roll over highlighting of the markers, the double Y axis in the chart, and overlay of the line chart onto the column chart. But I'll cover those in future posts.
HYDROGEN VIEWER