Turn fields off by script

4923
5
Jump to solution
12-06-2013 12:45 PM
MattEiben
Occasional Contributor
I've been beating my head against a wall for a full workday trying to figure this one out.  What I want to accomplish is to turn a number of fields off in a feature layer.  There is a method using the fieldInfo() method, but that only seems to work when creating a NEW feature layer.  I want to apply the turned off fields to the EXISTING layer.

Code example below

mxd = arcpy.mapping.MapDocument("CURRENT")  df = arcpy.mapping.ListDataFrames(mxd, "*")[0]  LayerNeedsFieldsTurnedOff = arcpy.mapping.ListLayers(mxd, "Layer Name", df)[0]  desiredFields = ["LAST","FIRST","CITY","ZIP"]  # This makes the field_info object that can then be applied to a layer field_info = arcpy.Describe(LayerNeedsFieldsTurnedOff).fieldInfo for index in xrange(0, field_info.count):     if field_info.getfieldname(index) not in engineFields:         field_info.setvisible(index,"HIDDEN")


This is where I'm not sure what to do, all the examples show making an new layer like:

arcpy.MakeFeatureLayer_management(LayerNeedsFieldsTurnedOff,"temp_layer","","",field_info)


This however set's me down a rabbit hole I really don't want to go down.  (duplicate layers, symbology, labeling, etc...) Is there a way to apply the field visibilities back to the original layer and not a new one?

Thanks in advance!
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor

I wasn't entirely satisfied with the following code, but seems to do the trick - it comes with the caveat that you have to 'manually' code other things like labeling.  Maybe I am missing something but found that since I 'stamped' what seems to be a new layer from the MFL execution to include the field_info obj, it dropped my labeling.  It also wrote 'temp_layer' in the Description property.  But my layer is written with at least the correct field_info settings.

import arcpy
arcpy.env.overwriteOutput = True
arcpy.env.addOutputsToMap = False
mxd = arcpy.mapping.MapDocument(r'your path to target mxd')
df = arcpy.mapping.ListDataFrames(mxd, '*')[0]
LayerNeedsFieldsTurnedOff = arcpy.mapping.ListLayers(mxd, 'your target layer name', df)[0]  

# fill in your desired fields to remain visible 
desiredFields = ['fieldname0', 'fieldname1', 'fieldname2', 'etc']  
field_info = arcpy.Describe(LayerNeedsFieldsTurnedOff).fieldInfo 
for i in range(field_info.count):     
    if field_info.getfieldname(i) not in desiredFields:
        field_info.setvisible(i, 'HIDDEN')
arcpy.MakeFeatureLayer_management(LayerNeedsFieldsTurnedOff, 'temp_layer', '', '', field_info)  
refLyr = arcpy.mapping.Layer('temp_layer')  

# rename the ref layer the same as your target layer 
refLyr.name = 'your target layer name'  
arcpy.ApplySymbologyFromLayer_management(refLyr, LayerNeedsFieldsTurnedOff) 
arcpy.mapping.UpdateLayer(df, LayerNeedsFieldsTurnedOff, refLyr, False)  
mxd.save()  

# clean up
if arcpy.Exists('temp_layer'):
     print '\'temp_layer\' still in memory...deleting now...'
     arcpy.Delete_management('temp_layer')
  print 'deleting obj refs...' 
del mxd,LayerNeedsFieldsTurnedOff, refLyr 
print 'done.'‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Just a further note - seems you could 'mine' properties from a lyr library or another mxd (or such library) to more easily 'reapply' these properties, for instance, like labeling.

-Wayne

View solution in original post

5 Replies
T__WayneWhitley
Frequent Contributor
Interesting...I haven't tried this but can you use the UpdateLayer command?

What I mean is, maybe it is possible to create a new layer obj (as you already know how to do) from your map feature layer, then go through similar steps as you seem to already have a handle on with your posted code, then 'stamp' your map layer object (using UpdateLayer) with your new layer object with the fieldInfo object associated with it (which has the fields turned on/off as you wish).

Does that make sense? - you already have most of the code and I am assuming you successfully defined the new layer field visibility?
When you ListLayers and get a handle on the appropriate layer within your mxd (or lyr), supposedly you can switch layer objects.  It's been a little while since I've tried it but think it works, see the syntax and webhelp ref below.  There are good bits of sample code at the webhelp or I can dig up some of my code later if you still need it.

Hope you get it going--
Wayne

UpdateLayer (data_frame, update_layer, source_layer, {symbology_only})

UpdateLayer (arcpy.mapping)
Desktop » Geoprocessing » ArcPy » Mapping module » Functions
http://resources.arcgis.com/en/help/main/10.2/index.html#//00s30000003p000000


EDIT:
By the way, there is a similar post I made here using the fieldInfo object to set the ratio policy of a 'new' feature layer to subsequently use in Intersect processing.  I'd like to test (when I get to my other computer) whether I can extend the code posted there to 'grab' the layers from a map doc and similarly set the visibility on the fieldInfo and combine that with the Intersect (or any other overlay processing) and use the output layer to update an existing lyr in the map doc.  It would not be a stretch...let me know how yours works.  If I remember, I will later post the test I just mentioned.
0 Kudos
MattEiben
Occasional Contributor
Thanks for your reply,

I think I understand the general idea you're getting at there.  My code left off with a field_info object needing to be assigned to a Layer.

I went ahead and did :

arcpy.MakeFeatureLayer_management(LayerNeedsFieldsTurnedOff,"temp_layer","","",field_info)


This resulted in a feature layer that does have the fields turned off as desired, though symbology and labeling got messed up (that can be fixed layer).

With the fields fixed in the "temp_layer", I used the arcpy.mapping.UpdateLayer like this:

tempLayer = arcpy.mapping.Layer("temp_layer")
arcpy.mapping.UpdateLayer(df,arcpy.mapping.Layer(LayerNeedsFieldsTurnedOff, tempLayer)


Unfortunately, it looks like the UpdateLayer method doesn't carry over the field information to the original layer.  The only method I've seen so far that even accepts the FieldInfo() object as an argument seems to be MakeFeatureLayer.

I suspect what I'm looking to do may not be possible with existing arcpy, as the layer docs show .fieldInfo as being a 'read only' property.
http://resources.arcgis.com/en/help/main/10.1/index.html#//018v00000063000000

If you have any sample code, I'd love to take a look at it though!  Probably won't be able to tinker with it until next week Monday though.
0 Kudos
T__WayneWhitley
Frequent Contributor

I wasn't entirely satisfied with the following code, but seems to do the trick - it comes with the caveat that you have to 'manually' code other things like labeling.  Maybe I am missing something but found that since I 'stamped' what seems to be a new layer from the MFL execution to include the field_info obj, it dropped my labeling.  It also wrote 'temp_layer' in the Description property.  But my layer is written with at least the correct field_info settings.

import arcpy
arcpy.env.overwriteOutput = True
arcpy.env.addOutputsToMap = False
mxd = arcpy.mapping.MapDocument(r'your path to target mxd')
df = arcpy.mapping.ListDataFrames(mxd, '*')[0]
LayerNeedsFieldsTurnedOff = arcpy.mapping.ListLayers(mxd, 'your target layer name', df)[0]  

# fill in your desired fields to remain visible 
desiredFields = ['fieldname0', 'fieldname1', 'fieldname2', 'etc']  
field_info = arcpy.Describe(LayerNeedsFieldsTurnedOff).fieldInfo 
for i in range(field_info.count):     
    if field_info.getfieldname(i) not in desiredFields:
        field_info.setvisible(i, 'HIDDEN')
arcpy.MakeFeatureLayer_management(LayerNeedsFieldsTurnedOff, 'temp_layer', '', '', field_info)  
refLyr = arcpy.mapping.Layer('temp_layer')  

# rename the ref layer the same as your target layer 
refLyr.name = 'your target layer name'  
arcpy.ApplySymbologyFromLayer_management(refLyr, LayerNeedsFieldsTurnedOff) 
arcpy.mapping.UpdateLayer(df, LayerNeedsFieldsTurnedOff, refLyr, False)  
mxd.save()  

# clean up
if arcpy.Exists('temp_layer'):
     print '\'temp_layer\' still in memory...deleting now...'
     arcpy.Delete_management('temp_layer')
  print 'deleting obj refs...' 
del mxd,LayerNeedsFieldsTurnedOff, refLyr 
print 'done.'‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Just a further note - seems you could 'mine' properties from a lyr library or another mxd (or such library) to more easily 'reapply' these properties, for instance, like labeling.

-Wayne

MattEiben
Occasional Contributor
This is exactly what I was looking for!  I was getting pretty close, but that neatly ties it up.  Thanks for the code sample.  🙂  Hopefully, ESRI makes fieldInfo() a write attribute in the future, that would make this a little less roundabout.  Thanks again!

Matt
0 Kudos
T__WayneWhitley
Frequent Contributor
Yes, I wholeheartedly agree...good catch.
If you will, go ahead and mark this thread answered so that it is closed.  You are new to the forum, so if you don't know how, just fiddle with the button controls over to the right of the posts.  You have to be logged in; you can only 'checkmark' one post, next to the one you feel represents the best answer (or, if you feel so inclined, do not mark an answer)...toggle up for points next to any posts you want to award.  That's it, oh and welcome to the forums - good start!

Enjoy,
Wayne
0 Kudos