How do I select features in a shapefile, zoom to extent and save a mxd to a directory?

2345
9
03-22-2017 03:25 PM
BryanMcPherson1
New Contributor

Hi - It's been 10 years since programming something .. in desperate need of assistance from this community.  I have a project that seems like an easy assignment but I forget the names of objects, calls, procedures, functions, etc. However programming theory is still ingrained into my head through years of doing it. There are 4 questions related to a project.

I'm not sure if ArcObjects or Python is the best way to approach it (advice here is also appreciated).

Context & questions below.

---

Context:

The project invlolves selecting a COMMUNITY name with multiple features located on a map. The data is stored in 3 separate shapefiles (points, lines & polys). For each COMMUNITY there are multiple IDs - we'll call them PINs. I want to create a series of maps (mxds) for all the PINs associated with that COMMUNITY.

Let's say the PIN is 8199. Since a PIN can be the form of a point, line & poly then all these features will be selected & zoomed to and appear on a map titled 8199 & saved to a directory. Then it moves onto the next PIN - 8200 and does the same thing.

I am aiming to do the following:

1) Have a button in the arcgis window that opens a msgbox (or combobox on the toolbar). The pulldown box will ask the user to select a COMMUNITY name. This will then set a COMMUNITY name for each of the 3 shapefiles.

Question # 1 -> How does one create a pulldown msgbox (or combobox on the toolbar) populated either from an existing feature table?  There are duplicate values for each COMMUNITY - is there a way to filter this to show only one instance (unique values) of each for the pulldown?

2) Select all the features for each point, line & poly layer (PIN = 8199). Maybe it is selected through a recordset,
or managed through a definition query .. I'm not sure - just looking for the easiest method.

Question # 2 -> What function, command or procedure is needed to do this?


3) Once all features are selected (PIN - 8199) it zooms to the extent of all the features selected.

Question # 3 -> What function, command or procedure is needed to zoom to all selected features?


4) Save the mxd based on 4 digit PIN selected into a directory.

Question # 4 -> What function, command or procedure is needed to save the mxd?

At this point it will move on to the next record in the recordset and do the same thing until the last record (maybe 50
or more in total maps). Ideally I would have a message box that states # of mxd's saved to the pathname
(ex: "47 maps saved to c:\gis\communitymaps")

---


I will be modifying this code and adding more bells & whistles as I go - but this is the start of it. Any help or support
from this forum is greatly appreciated.

Thank you.

- Bryan

0 Kudos
9 Replies
BrentHoskisson
Occasional Contributor III

Hi and welcome back to programming.  In the last 10 years a lot has changed in customizing ArcMap.  Since you put this into the ArcObject SDK section, here are the answers if you decide to use ArcObjects:   

#1

I suggest looking at ArcMap add-ins.  ArcObjects Help for .NET developers  This should have more than enough information to get you going.

#2

Really depends on how you want to proceed, you will probably create an IQueryFilter and then use that to select your features into an ISelectionSet with the FeatureClass.Select function.

#3 

To zoom to your objects, you will want to find the greatest extent around the objects and use the Extent function in the IActiveView interface in Carto.

#4 

A clarification, you don't save it to the MXD, you save it to some layer (Shapefile, etc.) and then load that layer into the MXD.

You will want to look at the IFeatureDataConverter2 interface in the Geodatabase section.  Specifically you will use the ConvertFeatureClass function with a SelectionSet option.

To add the layer to a map, just get the IMap interface and run the AddLayer function.

I am sure someone else will reply with information for Python scripting.

Good Luck

Brent

0 Kudos
BryanMcPherson1
New Contributor

Hi Brent - thank you kindly for all the suggestions.  I have taken a look and think that is plenty to get me started.

I'm a little confused on question #4.  For each PIN a map needs to be created that is zoomed to the full extent.  This map has symbology, surround text and other items associated with it in the map (mxd).  The project needs an mxd to be created for each PIN.  Is there not a simple method to either save or export the mxd by the PIN name & then move on to the next record?

Best

Bryan

0 Kudos
IanMurray
Frequent Contributor

Hi Bryan,

I actually do this fairly extensively, managing several thousand map documents that are automatically created based on ObjectIDs using python and the arcpy mapping module.

I use a search cursor to loop through each record in a geodatabase feature class, collect all the attribute information I need into variables and use them to subset my layers already on a map template and update text elements and other layout elements on my map.  It then saves a copy of the map using the ID number and other attributes and saves them to specified output folders.

Search Cursor

http://desktop.arcgis.com/en/arcmap/10.3/analyze/arcpy-data-access/searchcursor-class.htm

Help with Arcpy mapping module

https://community.esri.com/docs/DOC-1778

If you are going to use a map template as a base, I would recommend naming all the text and layout elements in the map you are wishing to change in order to make them easier to access via arcpy.mapping. 

If you are interested in this let me know and I can post some good starter code for you with examples for setting up a cursor, accessing map documents in memory, changing layout elements and querying layers in the TOC, changing the dataframe extent and scale, saving and exporting maps, etc.  However, I do not use a combo box as I designed my script to run standalone but I'm sure you could adapt it to a combo box if needed.

Ian

0 Kudos
BryanMcPherson1
New Contributor

Hi Ian - thank you for your response & suggestions regarding Search Cursor.

It sounds very close to what we are aiming to achieve.  Yes - please share some starting code if you don't mind doing so.  You could post here or send an email to me at bmcpherson@landactive.com

Best,

Bryan

0 Kudos
IanMurray
Frequent Contributor

I'm having a fairly busy workday today so can't really flesh out some starter code at the moment. 

I did dig up an old post I had where I posted a good portion of code I used for this function(Down towards the bottom).  Its fairly idiosyncratic to my set-up but should give plenty of examples for doing many of the things you would need to do for your map automation.

https://community.esri.com/thread/160192

BryanMcPherson1
New Contributor

Hi thank you Ian - this is enough to get me started.  If you think there is anything that would build on this then share when you have a chance.  I really appreciate your code from the previous thread.

Best,

Bryan

0 Kudos
IanMurray
Frequent Contributor

I suppose really on what exactly you are wanting to do with it and how your data is arranged.  I will say though that I have improved on that code pretty significantly and plan to do so again.  The biggest inefficiency in that script is everything takes place within the cursor which slows stuff down ALOT(It took 4 days to create about 4500 map documents and PDFs).    I'm planning to read everything to a dictionary in the future and then looping through the dictionary(See /blogs/richard_fairhurst/2014/11/08/turbo-charging-data-manipulation-with-python-cursors-and-diction... for help with that if you want to implement) and create the maps.  The other thing I changed significantly is I use definition queries to subset my layers now instead of selecting them and making a new layer each time. 

I have a few other tricks I've developed since then as well, such as turning layers on and off if they intersect with other layers, moving text elements to a location on a map with a fixed extent.  Scale bars can be tricky when working with multiple scales(I do everything in multiples of 1:1200, since most of my maps are of fairly small areas and my engineer likes everything nice and even on an engineering scale.), as are legends when all the classes may or may not be in the map extent.  I recommend planning out exactly how you want things to look for each map and test your script as you go on small subsets of your data to make sure it works as you think it should. 

I also cannot reiterate how important it is to go and name all the elements of whatever map templates you develop to make all the features easy to access with python.

If you have questions about anything feel free to ask.

Ian

0 Kudos
BryanMcPherson1
New Contributor

"The other thing I changed significantly is I use definition queries to subset my layers now instead of selecting them and making a new layer each time."

 

Do you have a sample of how you approached this?  It sounds like a perfect solution for my project.  As far as switching from a cursor approach to a dictionary approach - this is a good idea.   For now though we only need to run 100 maps at a time so cursors might be a better alternative for our project.  I will check into both solutions.

0 Kudos
IanMurray
Frequent Contributor

Ex.  Layer.definitionQuery = ' ID = ' + str(ID)

Layer Class help: http://desktop.arcgis.com/en/arcmap/10.3/analyze/arcpy-mapping/layer-class.htm

Once you create a layer object for the layer in the map, you can change its definition query property.  This example is using the ID field and the ID value pulled from the cursor.  Obviously you would need to change to your PIN value and field and you may or may not need a more complex expression if you are planning to use your Community values in your query as well.

See Joshua Bixby's post in the below thread about suggestions for python string formatting when writing SQL queries.

https://community.esri.com/thread/121098

0 Kudos