ThinkGeo.com    |     Documentation    |     Premium Support

Adding columns to a shapefile

Greetings.


I am loading a shapefile into a ShapeFileFeatureLayer in my application.  The way my data is structured from using 2.x is having a base shapefile, and a CSV that contains additional data.  In 2.x, I would open the shapefile, then add columns and data from the csv.



In 3.0, I'm not able to find how to add a column to the ShapeFileFeatureLayer, and then subsequently populate it.  



I know that you can add columns to an InMemoryFeatureLayer, and then populate it, but you can't load a shapefile into an InMemoryFeatureLayer (or can you).



How can I go about doing this?



Thanks.

Charley.



Charley,


There are two ways to do that.


First one is as you said using InMemoryFeatureLayer, add all the features as well as your own columns into InMemoryFeatureLayer with following code.




ShapeFileFeatureLayer shapeLayer = new ShapeFileFeatureLayer(@"..\..\SampleData\Data\Countries02.shp");
shapeLayer.Open();
Collection<Feature> allFeatures = shapeLayer.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns);
Collection<FeatureSourceColumn> columns = shapeLayer.QueryTools.GetColumns();

InMemoryFeatureLayer inMemoryLayer = new InMemoryFeatureLayer(columns, allFeatures);
inMemoryLayer.Columns.Add(new FeatureSourceColumn("MyColumn"));
for (int i = 0; i < inMemoryLayer.InternalFeatures.Count ; i++)
{
    inMemoryLayer.InternalFeatures[i].ColumnValues["MyColumn"] = "MyValue";
}


The second way is using worldLayer.FeatureSource.CustomColumnFetch event. But there is a known issue about it; it can’t work in some case and we will fix it later.


Thanks,

ThinkGeo Support

 



I’ve begun adding the items to the InMemoryFeatureLayer. The problem that I have, when I add items to the inMemoryFeature layer, I cannot just loop through them and add incrementally, as I need to ensure that the IDs are synched up.  
  
 This makes it quite slow to add the values to the Internal Features. I’m dealing with ~120 columns and ~12,000 rows. 
  
 
// Create columns from the the csv
DataTable table = DataFactory.CreateDataTable(filePath, true);

// Add the columns to the layer
foreach (DataColumn column in table.Columns)
{
    inMemoryLayer.Columns.Add(new FeatureSourceColumn(column.ColumnName));
}

// Add the data to each column in the layer
foreach (DataRow row in table.Rows)
{
    // Get the specific feature to add the data to the proper Id
    Feature feature = inMemoryLayer.InternalFeatures.Where(p => p.ColumnValues[“WSTATION”].ToString() == row[“GRIDID”].ToString()).Single();

    foreach (DataColumn column in table.Columns)
    {   
        feature.ColumnValues[column.ColumnName] = row[column.ColumnName].ToString();
    }                    
}
 
  
 Is there a better way to do this? In ThinkGeo 2.x, I had to build a hashtable and associate that to the CustomFields. It was much faster (~4 seconds vs ~30 seconds with the InternalFeatures).  
  
 Also, my Themes are not showing using the InMemoryFeature (as a StaticOverlay).  
  
 Thanks.  
 Charley. 


Thanks Charley, we will recreate and look into it.

Guys, 
  
  I think if you have that much data then I would try and stick with the shape file and use the custom field fetch.  I will find out what the issue Lee is referring to and see if we cant work it out now.  The way I would suggest doing things is to use your shapefile with a spatial index.  Next load your CSV file into a structure where you have a dictionary where the key is the record number and inside of that a dictionary where the key is the column name.  This way you will get the fast lookup.  The way the custom field fetch works is you use column names that do no exist in your styles and other places.  When we get the records we will see that you are using columns that do no exist and we raise an event with the column and feature and allow you to fill in the column data.  This sounds like exactly what you need.  If your data is in that dictionary in a dictionary then the lookup will be really fast and no need to move all your spatial data into memory. 
  
   If you decide to use the InMemeoryLayer then I highly suggest you use the IndexedInMemeoryFeatureLayer, you can find the code for this in the Developers Blog discussion forum, link below.  The reason is that the original InMemeoryFeatureLayer was not designed to hold vast amounts of spatial data and is in no way indexed.  This mean the lookup times are very bas when you have many or complex features.  The indexed version adds an in-memory spatial index that speeds this up a bunch.  There is a caveat in that when you add your features you need to add them through the edit API.  The discussion forum post goes into it.  This is because we build the index in the commit transaction overload.  Also at this time if you add features after the initial load then they are not in the spatial index.  This mean it is better suited for static data.  If you really had to add a feature later this could be supported but we have to re-build the spatial index and that takes a little time. 
  
 Like I said your best bet is the custom field fetch as is saves you memory and you get the result you want which is to integrate some external data without a hassle. 
  
 gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/16/aft/5266/afv/topic/Default.aspx 
  
 David